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
. А вот и полезная статья о том, как это делать.
IExceptionHandler
IExceptionHandler
— это интерфейс, который предоставляет разработчику обратный вызов для обработки известных исключений в центральном расположении.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
🎉🚀 Создание отказоустойчивых облачных сервисов с помощью .NET 8
В новой версии .NET добавлены пакеты
@csharp_1001_notes
В новой версии .NET добавлены пакеты
Microsoft.Extensions.Http.Resilience
и Microsoft.Extensions.Resilience
, основанные на библиотеке Polly. Их главная цель — упростить интеграцию отказоустойчивости в ваши приложения.
dotnet add package Microsoft.Extensions.Http.Resilience
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http.Resilience" />
</ItemGroup>
var services = new ServiceCollection();
services.AddHttpClient("my-client")
.AddStandardResilienceHandler(options =>
{
// Configure standard resilience options here
});
@csharp_1001_notes
long? catCode = null;
// Если строка val не пустая,
if (!(String.IsNullOrWhiteSpace(val)))
{
// распознаем в первых цифрах до пробела целое 64-битное число.
// Если его там нет, записываем в catCode NULL.
// Если его удалось распознать, записываем его в catCode.
if (!(Int64.TryParse(val.Split(" ")[0], out long cc)))
{
catCode = null;
}
else
{
catCode = cc;
}
}
Как переписать этот код чуть понятнее?
public static string LeftDigits(this string str)
{
if (str == null) return null;
if (!str.contains(" ") return null;
string left = str.Split(" ")[0];
if (! left.All(Char.IsDigit){
return null;
}
return left;
}
//...
string digits = LeftDigits(val);
long? catCode = digits != null ? Int64.Parse(digits) : null;
А есть ли ещё варианты?
Можете накидать свои в комментах
@csharp_1001_notes
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Преобразуйте базу данных SQL Server в базу данных SQLite из Code project.
https://codeproject.com/Articles/26932/Convert-SQL-Server-DB-to-SQLite-DB
https://github.com/karenpayneoregon/sqlserver-to-sqllite
@csharp_1001_notes
https://codeproject.com/Articles/26932/Convert-SQL-Server-DB-to-SQLite-DB
https://github.com/karenpayneoregon/sqlserver-to-sqllite
@csharp_1001_notes
Держите годное видео, в котором систематизируются знания о новых возможностях языка начиная с C#8 по C#11, а также обсуждаются на примерах новейшие возможности C# 12 и .NET 8.
@csharp_1001_notes
Please open Telegram to view this post
VIEW IN TELEGRAM
Реализация сервиса для сокращения URL-адресов с помощью .NET:
Создадим эндпоинты.
Первая принимает URL, создаёт короткий URL и возвращает его:
csharp
app.MapPost("shorten", async (
string url,
UrlShorteningService svc,
AppDbContext dbCtx,
HttpContext httpCtx) =>
{
if (!Uri.TryCreate(url, UriKind.Absolute, out _))
return Results.BadRequest(
"Предоставленный URL неверный.");
var code = await svc.GetCode();
var req = httpCtx.Request;
var shortUrl = new ShortUrl
{
Id = Guid.NewGuid(),
Url = url,
Code = code,
CreatedOn = DateTime.UtcNow
};
dbCtx.ShortenedUrls.Add(shortUrl);
await dbCtx.SaveChangesAsync();
return Results.Ok(
$"{req.Scheme}://{req.Host}/{code}");
});
Здесь возникает небольшая ситуация гонки, поскольку мы сначала генерируем уникальный код, а затем вставляем его в БД. Параллельный запрос может сгенерировать тот же уникальный код и вставить его в БД до того, как мы завершим транзакцию. Однако вероятность того, что это произойдет, невелика, кроме того, уникальный ключ в БД защищает нас от дублирования значений.
Второй эндпоинт перенаправит на исходный URL при доступе к сокращённому:
csharp
app.MapGet("{code}",
async (
string code,
AppDbContext dbCtx) =>
{
var shortUrl = await
dbCtx.ShortUrls
.SingleOrDefaultAsync(
s => s.Code == code);
if (shortUrl is null)
return Results.NotFound();
return Results.Redirect(shortUrl.Url);
});
Эта конечная точка ищет код в БД и, если он найден, перенаправляет пользователя на исходный длинный URL. Ответ будет иметь код состояния 302 (Found) согласно стандартам HTTP.
Недостатки и возможные улучшения
1. Недостатком реализации сервиса является длинная задержка, т.к. мы проверяем каждый генерируемый код в БД. Улучшением может стать заблаговременное создание уникальных кодов в БД.
2. Кэширование второй конечной точки позволит снизить нагрузку на БД для часто используемых коротких URL.
📌 Подробнее
@csharp_1001_notes
Please open Telegram to view this post
VIEW IN TELEGRAM