⚡️ CI/CD Workflow: упрощенный гайд от ByteByteGo 
CI/CD — это методология, которая позволяет автоматизировать процесс разработки и доставки ПО в продакшн.
Будь вы разработчиком, специалистом по DevOps, тестировщиком или занимаетесь любой современной ролью в ИТ, CI/CD пайплайны стали неотъемлемой частью процесса разработки.
@csharp_1001_notes
  CI/CD — это методология, которая позволяет автоматизировать процесс разработки и доставки ПО в продакшн.
Будь вы разработчиком, специалистом по DevOps, тестировщиком или занимаетесь любой современной ролью в ИТ, CI/CD пайплайны стали неотъемлемой частью процесса разработки.
@csharp_1001_notes
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Перехватчики в EF Core помогают перехватывать, изменять или подавлять операции EF Core.
Перехватчики регистрируются для каждого экземпляра DbContext при настройке контекста. Каждый перехватчик реализует интерфейс IInterceptor. Несколько распространённых производных интерфейсов включают
- IDbCommandInterceptor, 
- IDbConnectionInterceptor,
- IDbTransactionInterceptor,
- ISaveChangesInterceptor.
Вам не нкжно реализовывать эти интерфейсы напрямую.
Лучше использовать конкретные реализации и переопределить необходимые методы.
Вот вариант использования перехватчиков с помощью самого распространённого перехватчика
SaveChangesInterceptor, который добавляет поведение при сохранении изменений в базе данных.Добавление записей аудита
Записи аудита изменений сущностей - ценная функция в некоторых приложениях. Вы записываете дополнительную информацию аудита каждый раз, когда объект создаётся или изменяется. Также это могут быть значения «до» и «после», в зависимости от ваших требований.
Например, создадим интерфейс IAuditable с датами создания и изменения объекта:
public interface IAuditable
{
  DateTime Created { get; }
  DateTime? Modified { get; }
}Добавим UpdateInterceptor для записи значений аудита. Он использует ChangeTracker для поиска всех экземпляров IAuditable и устанавливает соответствующее значение свойства. Здесь мы используем метод SavingChangesAsync, который запускается до того, как изменения будут сохранены в БД.
internal sealed class UpdateInterceptor 
 : SaveChangesInterceptor
{
  public override 
   ValueTask<InterceptionResult<int>> 
   SavingChangesAsync(
     DbContextEventData e,
     InterceptionResult<int> result,
     CancellationToken ct = default)
  {
    if (e.Context is not null)
      UpdateEntities(e.Context);
    return base
     .SavingChangesAsync(e, result, ct);
  }
  private static void 
   UpdateEntities(DbContext ctx)
  {
    var now = DateTime.UtcNow;
    var entities = ctx
     .ChangeTracker
     .Entries<IAuditable>()
     .ToList();
    foreach (var e in entities)
    {
      if (e.State == EntityState.Added)
        e.Property(
         nameof(IAuditable.Created)) = now;
      if (e.State == EntityState.Modified)
        e.Property(
         nameof(IAuditable.Modified)) = now;
    }
  }
}
Эту реализацию можно легко расширить, включив в неё, например, информацию о текущем пользователе.
Зарегистрировать перехватчик можно следующим образом:
services.AddSingleton<UpdateInterceptor>();
services.AddDbContext<
  IApplicationDbContext, 
  AppDbContext>(
   (sp, opts) => opts
     .UseSqlServer(connString)
     .AddInterceptors(
      sp.GetRequiredService<UpdateInterceptor>());👉 Подробнее
@csharp_1001_notes
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Эта статья знакомит с концепцией отказоустойчивости и хаос-инженерии в приложениях .NET с использованием библиотеки Polly и рассказывает о новых возможностях, позволяющих использовать хаос-инженерию.
В ней приведено практическое руководство по интеграции стратегий хаоса в HTTP-клиенты и показывается, как настраивать конвейеры отказоустойчивости для повышения эффективности работы вашего приложения.
▪Статья
▪Polly
@csharp_1001_notes
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Шаблон Хранитель используется, когда:
▪необходимо сохранить снимок состояния объекта (или его части) для последующего восстановления
▪прямой интерфейс получения состояния объекта раскрывает детали реализации и нарушает инкапсуляцию объекта
В C# паттерн Memento может быть реализован с помощью комбинации трех классов:
Originator, Memento и Caretaker.
▪ Подробнее
@csharp_1001_notes
Please open Telegram to view this post
    VIEW IN TELEGRAM
  EF 8 генерирует бодее эффективные запросы, используя 
Разницу в запросах вы можете увидеть в примере на картинке.
@csharp_1001_notes
  IN вместо EXISTS, когда метод Contains используется с подзапросом.Разницу в запросах вы можете увидеть в примере на картинке.
@csharp_1001_notes
▪Часть 1
▪Часть2
@csharp_1001_notes
Please open Telegram to view this post
    VIEW IN TELEGRAM
  System.IO.Hashing  - это действительно полезный пакет 
📌Узнать о нем подробнее
@csharp_1001_notes
  NuGet для некриптографического хэширования в .NET.📌Узнать о нем подробнее
@csharp_1001_notes
⚡️ AspNetCore.ApiGateway
Представляем крутой инструмент: микросервис с конвейером запросов #ASPNETCore.
Без проблем перейдите от веб-интерфейса #ASPNETCore к Veritas API Gateway, в который входят, Swagger, методы авторизации, фильтры, балансировщик нагрузки и многое другое.
▪ Github
@csharp_1001_notes
  Представляем крутой инструмент: микросервис с конвейером запросов #ASPNETCore.
Без проблем перейдите от веб-интерфейса #ASPNETCore к Veritas API Gateway, в который входят, Swagger, методы авторизации, фильтры, балансировщик нагрузки и многое другое.
▪ Github
@csharp_1001_notes
⚡️ Параллельная Публикация Уведомлений в MediatR
MediatR — это популярная библиотека с простой реализацией паттерна посредник в .NET.
С ростом популярности паттерна
Издатель — подписчик — поведенческий шаблон проектирования передачи сообщений, в котором отправители сообщений, именуемые издателями (англ. publishers), напрямую не привязаны программным кодом отправки сообщений к подписчикам (англ. subscribers).
Но она также поддерживает паттерн издатель-подписчик с использованием уведомлений. Можно опубликовать экземпляр INotification, и несколько подписчиков обработают опубликованное сообщение.
Разберемся как это можно делать параллельно.
Нам нужен класс, реализующий INotification:
Реализация по умолчанию - ForeachAwaitPublisher:
Но вы также можете использовать TaskWhenAllPublisher (показаны только отличия в реализации метода Publish:
Настройка стратегии публикации происходит в методе AddMediatR.
Если вы хотите использовать стратегию TaskWhenAllPublisher, вы можете:
- указать значение для свойства NotificationPublisher (тогда издатель будет синглтоном),
- указать тип стратегии в свойстве NotificationPublisherType и использовать свойство ServiceLifetime для задания времени жизни:
Плюсы
Параллельного запуска обработчиков уведомлений обеспечивает значительное повышение производительности по сравнению с поведением по умолчанию.
Однако обратите внимание, что все обработчики будут использовать одну и ту же область видимости. Если у вас есть экземпляры сервисов, которые не поддерживают конкурентный доступ, вы можете столкнуться с проблемами. К сожалению, одним из таких является EF Core DbContext.
📌 Подробнее
@csharp_1001_notes
  MediatR — это популярная библиотека с простой реализацией паттерна посредник в .NET.
Посредник — паттерн шаблон проектирования, обеспечивающий взаимодействие множества объектов, формируя при этом слабое зацепление и избавляя объекты от необходимости явно ссылаться друг на друга.С ростом популярности паттерна
CQRS MediatR стала популярной библиотекой для реализации команд и запросов.Издатель — подписчик — поведенческий шаблон проектирования передачи сообщений, в котором отправители сообщений, именуемые издателями (англ. publishers), напрямую не привязаны программным кодом отправки сообщений к подписчикам (англ. subscribers).
Но она также поддерживает паттерн издатель-подписчик с использованием уведомлений. Можно опубликовать экземпляр INotification, и несколько подписчиков обработают опубликованное сообщение.
Разберемся как это можно делать параллельно.
Нам нужен класс, реализующий INotification:
public record OrderCreated(Guid OrderId) : INotification;
А также реализация соответствующего INotificationHandler:public class OrderCreatedHandler : 
 INotificationHandler<OrderCreated>
{
  private readonly INotificationService svc;
  public OrderCreatedHandler(
   INotificationService service)
  {
    svc = service;
  }
  public async Task Handle(
   OrderCreated notification,
   CancellationToken ct)
  {
    await svc.SendOrderCreatedEmail(
     notification.OrderId,
     ct);
  }
}
Теперь можно публиковать сообщение с помощью IMediator или IPublisher:
await publisher.Publish(
  new OrderCreated(order.Id), 
  cancellationToken);
MediatR вызовет все соответствующие обработчики. До 12й версии MediatR стратегия публикации вызывала каждый обработчик по отдельности. Однако появился новый интерфейс INotificationPublisher, управляющий тем, как вызываются обработчики.
Реализация по умолчанию - ForeachAwaitPublisher:
public class ForeachAwaitPublisher 
 : INotificationPublisher
{
  public async Task Publish(
    IEnumerable<NotificationHandlerExecutor> executors,
    INotification notification,
    CancellationToken ct)
  {
    foreach (var e in executors)
    {
      await e
       .HandlerCallback(notification, ct)
       .ConfigureAwait(false);
    }
  }
}
Она вызывает обработчики по одному и завершается неудачей при ошибке в одном из обработчиков.
Но вы также можете использовать TaskWhenAllPublisher (показаны только отличия в реализации метода Publish:
var tasks = executors
  .Select(e =>
    e.HandlerCallback(notification, ct))
  .ToArray();
return Task.WhenAll(tasks);
TaskWhenAllPublisher вызывает все обработчики одновременно и выполняет их все независимо от того, возникали ли в них ошибки. Если вы сохраните задачу, возвращенную TaskWhenAllPublisher, вы можете получить доступ к свойству Task.Exception, содержащему экземпляр AggregateException, и реализовать обработку исключений.
Настройка стратегии публикации происходит в методе AddMediatR.
Если вы хотите использовать стратегию TaskWhenAllPublisher, вы можете:
- указать значение для свойства NotificationPublisher (тогда издатель будет синглтоном),
- указать тип стратегии в свойстве NotificationPublisherType и использовать свойство ServiceLifetime для задания времени жизни:
services.AddMediatR(cfg => {
  …
  cfg.NotificationPublisher = 
   new TaskWhenAllPublisher();
  // или 
  cfg.NotificationPublisherType = 
   typeof(TaskWhenAllPublisher);
  cfg.ServiceLifetime = ServiceLifetime.Transient;
});
Вы также можете реализовать пользовательский экземпляр INotificationPublisher и вместо этого использовать собственную реализацию.
Плюсы
Параллельного запуска обработчиков уведомлений обеспечивает значительное повышение производительности по сравнению с поведением по умолчанию.
Однако обратите внимание, что все обработчики будут использовать одну и ту же область видимости. Если у вас есть экземпляры сервисов, которые не поддерживают конкурентный доступ, вы можете столкнуться с проблемами. К сожалению, одним из таких является EF Core DbContext.
📌 Подробнее
@csharp_1001_notes
⚡️ Каждый разработчик должен знать о тестовых контейнерах. Это отличный инструмент, который нужно знать и применять, когда он вам понадобится.
Вот пример работы с Testcontainersна .NET:
https://testcontainers.com/guides/getting-started-with-testcontainers-for-dotnet/
#dotnet #csharp #fsharp
@csharp_1001_notes
  Вот пример работы с Testcontainersна .NET:
https://testcontainers.com/guides/getting-started-with-testcontainers-for-dotnet/
#dotnet #csharp #fsharp
@csharp_1001_notes
🚀 Text2sql
Нейросеть, специализирующаяся на написании SQL-запросов (и не только) по текстовому описанию
Описание:
Ответ нейросети:
🔗 text2sql.ai
@csharp_1001_notes
  Нейросеть, специализирующаяся на написании SQL-запросов (и не только) по текстовому описанию
Описание:
A Regex expression to match a password that contains at least one lowercase letter, one uppercase letter, one digit, one special character, and is at least 8 characters long
Ответ нейросети:
^(?=.*d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()_+}{":;'/?.><,])(?=.*[^s]).{8,}$🔗 text2sql.ai
@csharp_1001_notes
aspire dashboard, работающим как автономный контейнер.https://learn.microsoft.com/en-us/samples/dotnet/aspire-samples/aspire-standalone-dashboard/
@csharp_1001_notes
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Задача: реализуй на C# метод расширения для строки, который будет проверять, является ли данная строка палиндромом.
Палиндром — это слово/фраза/последовательность символов, которая читается одинаково в обе стороны ("шалаш", "ротор", "12321")
Получилось?
Можешь смотреть код возможного решения
#junior
@csharp_1001_notes
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Относительно недавно на свет появился ASP.NET Core 8.0, и теперь можно обрабатывать ошибки с помощью
IExceptionHandler. А вот и полезная статья о том, как это делать.
IExceptionHandlerIExceptionHandler — это интерфейс, который предоставляет разработчику обратный вызов для обработки известных исключений в центральном расположении.IExceptionHandler реализации регистрируются путем вызова IServiceCollection.AddExceptionHandler. Время существования экземпляра IExceptionHandler — одноэлементное. Можно добавить несколько реализаций, и они вызываются в порядке регистрации.Если обработчик исключений обрабатывает запрос, он может вернуться
true к остановке обработки. Если исключение не обрабатывается обработчиком исключений, то элемент управления возвращается к поведению по умолчанию и параметрам из по промежуточного слоя. Для обработки и необработанных исключений создаются различные метрики и журналы.@csharp_1001_notes
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Разберём на примере.
Console.WriteLine("Start Main");
// Запускаем задачу PrintAsync и спокойно идём дальше
var printTask = PrintAsync();
Console.WriteLine("End Main");
// Ждём завершения задачи PrintAsync
await printTask;
async Task PrintDelayAsync()
{
    // Ждём 3 секунды, но при этом поток не будет занят
    await Task.Delay(3000);
    Console.WriteLine("Print");
}
async Task PrintAsync()
{
    Console.WriteLine("Start PrintAsync");
    // Ждём пока метод отработает, но поток не занят
    await PrintDelayAsync();
    Console.WriteLine("End PrintAsync");
}await этот поток освобождается может выполнять какие-то другие асинхронные задачи из вашего кода, если они у вас будут.Console.WriteLine("Start Main");
await PrintAsync();
Console.WriteLine("End Main");
async Task Print1Async()
{
    await Task.Delay(3000);
    Console.WriteLine("Print 1");
}
async Task Print2Async()
{
    await Task.Delay(2000);
    Console.WriteLine("Print 2");
}
async Task Print3Async()
{
    await Task.Delay(1000);
    Console.WriteLine("Print 3");
}
async Task PrintAsync()
{
    Console.WriteLine("Start PrintAsync");
    var tasks = new List<Task>() { Print1Async(), Print2Async(), Print3Async() };
    await Task.WhenAll(tasks);
    Console.WriteLine("End PrintAsync");
}Start Main
Start PrintAsync
Print 3
Print 2
Print 1
End PrintAsync
End Main
@csharp_ci
Please open Telegram to view this post
    VIEW IN TELEGRAM
  О паттерне «Спецификация», который позволяет улучшить структуру приложения, и, следовательно, увеличить гибкость, уменьшив при этом объем кода, а значит - сократить количество ошибок, но это не точно.
@csharp_1001_notes
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Please open Telegram to view this post
    VIEW IN TELEGRAM
  Итак кейс: выполняется некоторый код, выбрасывается исключение
NullReferenceException со следующим сообщением:Object reference not set to an instance of an object (В экземпляре объекта не задана ссылка на объект)
Что же это значит, и как исправить код?
Вы пытаетесь воспользоваться чем-то, что равно
null (или Nothing в VB.NET). Это означает, что либо вы присвоили это значение, либо вы ничего не присваивали.Как и любое другое значение,
null может передаваться от объекта к объекту, от метода к методу. Если нечто равно null в методе "А", вполне может быть, что метод "В" передал это значение в метод "А".Если среда выполнения выбрасывает
NullReferenceException, то это всегда означает: вы пытаетесь воспользоваться ссылкой. И эта ссылка не инициализирована (или уже не инициализирована).Это означает, что ссылка равна
null, а вы не сможете вызвать методы через ссылку, равную null, как тут:string foo = null;
foo.ToUpper();
Этот код выбросит исключение
NullReferenceException на 2 строке, потому что вы не можете вызвать метод ToUpper() у ссылки на string, равной null.Как определить источник ошибки?
Общие рекомендации: поставьте точки останова в ключевых местах, изучите значения переменных, расположив курсор мыши над переменной, либо открыв панели для отладки: Watch, Locals, Autos.
Если вы хотите определить место, где значение ссылки устанавливается (или нет), нажмите ПКМ на её имени и выберите "Find All References". Затем вы можете поставить точки останова на каждой найденной строке и запустить приложение в режиме отладки. Каждый раз, когда отладчик остановится на точке останова, вы можете удостовериться, что значение верное.
Так вы придёте к месту, где значение ссылки не должно быть
null, и определите, почему не присвоено верное значение.@csharp_ci
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Как видно из бенчмарков, это сейчас вообще самый быстрый сервер структур данных на всём диком западе:
Практически полностью совместим с Redis на уровне API, но при этом:
@csharp_ci
Please open Telegram to view this post
    VIEW IN TELEGRAM
  Как видно из бенчмарков, это сейчас вообще самый быстрый сервер структур данных на всём диком западе:
Практически полностью совместим с Redis на уровне API, но при этом:
@csharp_1001_notes
Please open Telegram to view this post
    VIEW IN TELEGRAM