C# 1001 notes
6.54K subscribers
313 photos
10 videos
2 files
301 links
Регулярные короткие заметки по C# и .NET.

Просто о сложном для каждого.

admin - @haarrp
Download Telegram
🖥 SQL в Фокусе: Полное Руководство. 100 ключевых Вопросов с собеседований

Часть 1
Часть2

@csharp_1001_notes
Please open Telegram to view this post
VIEW IN TELEGRAM
System.IO.Hashing - это действительно полезный пакет NuGet для некриптографического хэширования в .NET.

📌Узнать о нем подробнее

@csharp_1001_notes
⚡️ AspNetCore.ApiGateway

Представляем крутой инструмент: микросервис с конвейером запросов #ASPNETCore.

Без проблем перейдите от веб-интерфейса #ASPNETCore к Veritas API Gateway, в который входят, Swagger, методы авторизации, фильтры, балансировщик нагрузки и многое другое.

Github

@csharp_1001_notes
Please open Telegram to view this post
VIEW IN TELEGRAM
⚡️ Каждый разработчик должен знать о тестовых контейнерах. Это отличный инструмент, который нужно знать и применять, когда он вам понадобится.

Вот пример работы с Testcontainersна .NET:

https://testcontainers.com/guides/getting-started-with-testcontainers-for-dotnet/

#dotnet #csharp #fsharp

@csharp_1001_notes
🚀 Text2sql
Нейросеть, специализирующаяся на написании 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
🖥 Новый пример, показывающий, как использовать открытые API-интерфейсы телеметрии с 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
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Обработка ошибок с помощью IExceptionHandler в ASP.NET Core 8.0

Относительно недавно на свет появился ASP.NET Core 8.0, и теперь можно обрабатывать ошибки с помощью IExceptionHandler.
А вот и полезная статья о том, как это делать.

Вкратце о IExceptionHandler
IExceptionHandler — это интерфейс, который предоставляет разработчику обратный вызов для обработки известных исключений в центральном расположении.

IExceptionHandler реализации регистрируются путем вызова IServiceCollection.AddExceptionHandler. Время существования экземпляра IExceptionHandler — одноэлементное. Можно добавить несколько реализаций, и они вызываются в порядке регистрации.

Если обработчик исключений обрабатывает запрос, он может вернуться true к остановке обработки. Если исключение не обрабатывается обработчиком исключений, то элемент управления возвращается к поведению по умолчанию и параметрам из по промежуточного слоя. Для обработки и необработанных исключений создаются различные метрики и журналы.

📎 Статья
📎 Доки от Windows, как обрабатывать ошибки

@csharp_1001_notes
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 В чем преимущества асинхронного кода на C#?

Разберём на примере.
Вот, полностью асинхронный код:
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


То есть суть в чём — запустились сразу 3 задачи, выполнились они не в том порядке, как были запущены, а где меньше задержка, та раньше и выполнилась. При этом, повторюсь, достаточно одного потока, чтобы выполнять этот код. Что очень существенно, когда речь идёт о сильно загруженных программах типа веб-сервера или какого-то обработчика данных реального времени.

@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Интересная статья о паттерне «Спецификация» в С#

О чём статья?
О паттерне «Спецификация», который позволяет улучшить структуру приложения, и, следовательно, увеличить гибкость, уменьшив при этом объем кода, а значит - сократить количество ошибок, но это не точно.

К статье приложен пример Web API приложения, написанный с использованием анемичной доменной модели, библиотеки MediatR, Postgres и Docker Compose. Всё, как Вы любите и, таки да, анемичной доменной моделью мы нарушим инкапсуляцию, без этого никуда.

📎 Статья

@csharp_1001_notes
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Моя коллекция 50+ вопросов для собеса C#

https://habr.com/ru/articles/801369/

@csharp_1001_notes
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥Что такое NullReferenceException, и как исправить?

Итак кейс: выполняется некоторый код, выбрасывается исключение 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
🖥 Garnet — кэш от Microsoft, написан на C#, уделывает и Redis, и Dragonfly

Как видно из бенчмарков, это сейчас вообще самый быстрый сервер структур данных на всём диком западе:

Практически полностью совместим с Redis на уровне API, но при этом:
Имеет либеральную MIT лицензию, как и все последние крупные проекты MS, и этим крайне выгодно отличается от Redis
Написан на C#, и позволяет удобно расширять сервер
Делает по производительности и Redis, написанный на C, и Dragonfly написанный на C++

🖥 GitHub

@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Garnet — кэш от Microsoft, написан на C#, уделывает и Redis, и Dragonfly

Как видно из бенчмарков, это сейчас вообще самый быстрый сервер структур данных на всём диком западе:

Практически полностью совместим с Redis на уровне API, но при этом:
Имеет либеральную MIT лицензию, как и все последние крупные проекты MS, и этим крайне выгодно отличается от Redis
Написан на C#, и позволяет удобно расширять сервер
Делает по производительности и Redis, написанный на C, и Dragonfly написанный на C++

🖥 GitHub

@csharp_1001_notes
Please open Telegram to view this post
VIEW IN TELEGRAM
🎉🚀 Создание отказоустойчивых облачных сервисов с помощью .NET 8

В новой версии .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
🖥 Прочитать Nullable<long> из строки

Итак, дан код:

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
🖥 Что полезного в новых версиях C#

Держите годное видео, в котором систематизируются знания о новых возможностях языка начиная с C#8 по C#11, а также обсуждаются на примерах новейшие возможности C# 12 и .NET 8.

📎 YouTube

@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
🖥 Необходимо определить делегат и реализовать метод

Итак, вот задание:
определить делегат bool CounterHashSetDelegate(int a) и реализовать метод int Function12(HashSet<int> intSet, CounterHashSetDelegate filter), который возвращает количество элементов из intSet, которые удовлетворяют условию filter.
public static  class 
{
public delegate bool CounterHashSetDelegate(int a);
public static int Function12(HashSet<int> intSet, CounterHashSetDelegate filter)
{

int count = 0;
foreach (int i in intSet)
{
if(filter(i))
count++;
}
return count;
}
}



Давайте сразу к сути, решение может выглядеть так:
public delegate bool CounterHashSetDelegate(int a);

class Program
{
static void Main(string[] args)
{
CounterHashSetDelegate d = IsEvenNum;

Console.WriteLine($"Количество четных элементов:{Function12(new HashSet<int> { 1, 2, 3, 4, 5 }, d)}");

d = IsGreaterThen;

Console.WriteLine($"Количество элементов > 2:{Function12(new HashSet<int> { 1, 2, 3, 4, 5 }, d)}");

Console.ReadKey();
}

public static bool IsEvenNum(int a)
{
return a % 2 == 0;// четное ли число например
}

public static bool IsGreaterThen(int a)
{
return a > 2;//больше ли например
}


public static int Function12(HashSet<int> intSet, CounterHashSetDelegate filter)
{

int count = 0;
foreach (int i in intSet)
{
if (filter(i))
{
count++;
}
}
return count;
}

}

Вот и все дела

@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM