C# (C Sharp) programming
По всем вопросам- @notxxx1 Реестр РКН: https://clck.ru/3Fk3kb #VRHSZ
Show more📈 Analytical overview of Telegram channel C# (C Sharp) programming
Channel C# (C Sharp) programming (@csharp_ci) in the Russian language segment is an active participant. Currently, the community unites 18 130 subscribers, ranking 7 075 in the Technologies & Applications category and 36 514 in the Russia region.
📊 Audience metrics and dynamics
Since its creation on невідомо, the project has demonstrated rapid growth, gathering an audience of 18 130 subscribers.
According to the latest data from 25 August, 2026, the channel demonstrates stable activity. Although there has been a change in the number of participants by -72 over the last 30 days and by 5 over the last 24 hours, overall reach remains high.
- Verification status: Not verified
- Engagement rate (ER): The average audience engagement rate is 14.84%. Within the first 24 hours after publication, content typically collects 7.23% reactions from the total number of subscribers.
- Post reach: On average, each post receives 2 691 views. Within the first day, a publication typically gains 1 311 views.
- Reactions and interaction: The audience actively supports content: the average number of reactions per post is 0.
- Thematic interests: Content is focused on key topics such as .net, api, логика, архитектура, string.
📝 Description and content policy
The author describes the resource as a platform for expressing subjective opinions:
“По всем вопросам- @notxxx1
Реестр РКН: https://clck.ru/3Fk3kb
#VRHSZ”
Thanks to the high frequency of updates (latest data received on 26 August, 2026), the channel maintains relevance and a high level of publication reach. Analytics show that the audience actively interacts with content, making it an important point of influence in the Technologies & Applications category.
var user = await pipeline.ExecuteAsync(
async token => await httpClient.GetAsync("api/users", token)
);
Чистый код, единая стратегия обработки ошибок и меньше боли при росте микросервисов.
Если пишете на C# и строите production-системы — Resilience Pipelines стоит добавить в свой toolbox. ⚙️
builder.Services.AddRateLimiter(options =>
{
options.AddPolicy("fixed-by-ip", httpContext =>
RateLimitPartition.GetFixedWindowLimiter(
partitionKey: httpContext.Connection.RemoteIpAddress?.ToString(),
factory: _ => new FixedWindowRateLimiterOptions
{
PermitLimit = 10,
Window = TimeSpan.FromMinutes(1)
}));
});
В этом примере один IP может сделать максимум 10 запросов за минуту.
Но использовать такой подход вслепую не стоит.
Причина простая: реальные пользователи могут находиться за NAT, прокси или корпоративным шлюзом и иметь один внешний IP. В итоге лимит одного человека начнёт влиять на остальных.
Поэтому для авторизованных пользователей обычно лучше ограничивать запросы по уникальному userId.
А rate limit по IP оставлять для анонимных endpoint'ов, защиты от простых ботов или как дополнительный слой защиты.
Install-Package Steeltoe.Discovery.Consul
Регистрируем discovery:
builder.Services
.AddServiceDiscovery(o => o.UseConsul());
В appsettings.json указываем Consul и параметры сервиса:
"Consul": {
"Host": "localhost",
"Port": 8500,
"Discovery": {
"ServiceName": "reporting-service",
"Hostname": "reporting-api",
"Port": 8080
}
}
А дальше самое полезное:
builder.Services
.AddHttpClient<ReportingServiceClient>(client =>
{
client.BaseAddress = new Uri("http://reporting-service");
})
.AddServiceDiscovery()
.AddRoundRobinLoadBalancer();
То есть HttpClient ходит не на конкретный IP:port, а на логическое имя сервиса.
Steeltoe через Consul получает живые инстансы, а RoundRobinLoadBalancer распределяет запросы между ними.
Это особенно полезно, когда сервисы часто пересоздаются, IP меняются, а хардкодить адреса уже невозможно.
По сути, клиентская часть получает простой pipeline:
service name → Consul → healthy instances → load balancing → HTTP request
Для микросервисов на .NET это намного чище, чем городить собственный discovery layer.break и continue: теперь можно явно указать, из какого цикла выходить или какой цикл продолжать. Ещё появились union patterns и улучшенная проверка исчерпывающих случаев для закрытых иерархий типов.
В Runtime добавили оптимизации async`/`await, включая runtime async tiering и tail-await. Отдельно продолжают развивать NativeAOT и JIT.
В SDK NativeAOT-версия dotnet CLI теперь включена по умолчанию, как и MSBuild Server. У dotnet test появились общий --timeout, ограничение --maximum-failed-tests и поддержка запуска тестов на устройствах .NET MAUI.
ASP.NET Core получил автоматическую приостановку неактивных Blazor circuits, кеширование SSR через CacheView, новые анализаторы Blazor и встроенную локализацию validation-сообщений.
Ещё из приятного: HTTP request compression, API для DNS-записей, парольная защита ZIP, Complex<T>, улучшения LINQ в EF Core и поддержка Half в SQLite.
.NET 11 Preview 7 вышел 11 августа 2026 года и уже доступен для тестирования.
https://devblogs.microsoft.com/dotnet/dotnet-11-preview-7/Application внезапно начал зависеть от Infrastructure.
Code Review тоже не гарантирует, что такое заметят.
Для этого можно использовать Architecture Tests — тесты, которые проверяют не бизнес-логику, а структуру проекта.
Например, через NetArchTest.Rules:
[Fact]
public void Application_Should_Not_Depend_On_Infrastructure()
{
var result = Types
.InAssembly(ApplicationAssembly)
.ShouldNot()
.HaveDependencyOn("MyApp.Infrastructure")
.GetResult();
Assert.True(result.IsSuccessful);
}
Теперь случайный:
Application → Infrastructure
сломает CI так же, как обычный упавший unit-тест.
Можно зафиксировать и naming convention:
[Fact]
public void Handlers_Should_End_With_Handler()
{
var result = Types
.InAssembly(ApplicationAssembly)
.That()
.ImplementInterface(typeof(ICommandHandler<>))
.Should()
.HaveNameEndingWith("Handler")
.GetResult();
Assert.True(result.IsSuccessful);
}
Или заставить сервисы быть sealed:
Types
.InAssembly(ApplicationAssembly)
.That()
.HaveNameEndingWith("Service")
.Should()
.BeSealed();
Особенно полезно это становится в больших Clean Architecture / DDD / Modular Monolith проектах.
Вместо документа:
❌ «Application не должен зависеть от Infrastructure»
получаем исполняемое правило:
✅ нарушил архитектуру → тест упал → PR не прошёл
По сути, архитектура превращается из договорённости команды в часть автоматической проверки проекта.
#CSharp #DotNet #Architecture #Testingawait, хотя под капотом работают две независимые очереди:
Requester -> request -> Responder
Requester <- response <- Responder
В RabbitMQ запрос обычно содержит ReplyTo и уникальный CorrelationId, чтобы клиент понял, к какому запросу относится ответ.
В NATS для ответа создаётся отдельный inbox subject.
Упрощённая идея на C#:
var requestId = Guid.NewGuid();
await bus.SendAsync(new PriceRequest(
RequestId: requestId,
ProductId: productId
));
var response = await responses
.WaitForAsync<PriceResponse>(
requestId,
timeout: TimeSpan.FromSeconds(2),
cancellationToken);
Плюсы действительно значительные:
- отправителю не нужно знать адрес обработчика;
- responder можно горизонтально масштабировать;
- брокер помогает пережить кратковременный сбой сервиса;
- приложения остаются слабо связанными.
Но это не «HTTP, только через RabbitMQ».
Пока requester ждёт результат, взаимодействие остаётся логически синхронным. Поэтому обязательно нужны:
- таймаут и CancellationToken;
- уникальный CorrelationId;
- обработка поздних и повторных ответов;
- идемпотентность responder;
- ограничение количества одновременных запросов;
- трассировка через обе очереди.
Особенно опасный случай:
Service A ждёт B
Service B ждёт C
Service C ждёт A
Брокер работает, сообщения доставляются, но вся система стоит.
Request-response через messaging полезен, когда нужны location transparency, балансировка обработчиков и единый транспорт между сервисами.
Для простого короткого запроса HTTP или gRPC часто остаются понятнее и быстрее.
Главное правило:
брокер убирает прямую связь между сервисами, но не убирает зависимость от ответа.safe — но это не аналог Rust
В C# 15 тестируется новый контекстный модификатор safe для кода на границе с нативной памятью.
Главная проблема P/Invoke: компилятор видит сигнатуру метода, но не может проверить, насколько безопасно ведёт себя код внутри подключённой библиотеки. Теперь разработчик должен явно зафиксировать решение:
[LibraryImport("libc")]
internal static safe partial int getpid();
[LibraryImport("libc")]
internal static unsafe partial nuint strlen(byte* value);
safe означает, что вызов не требует `unsafe`-контекста со стороны пользователя API.
unsafe предупреждает: безопасность зависит от условий, которые компилятор проверить не может. Такой метод разрешено вызывать только внутри блока:
unsafe
{
nuint length = strlen(pointer);
}
Та же логика применяется к полям структур с явным расположением памяти:
[StructLayout(LayoutKind.Explicit)]
struct Packet
{
[FieldOffset(0)]
public safe long Id;
[FieldOffset(0)]
public unsafe nint Pointer;
}
Если не указать ни safe, ни unsafe, компилятор выдаст ошибку при включённых новых правилах безопасности. :contentReference[oaicite:0]{index=0}
Важный нюанс: safe не анализирует нативный код и не доказывает его безопасность. Это явное обещание автора API, которое делает потенциально опасные границы заметными при ревью.
C# постепенно меняет подход к unsafe: риск должен быть обозначен в контракте метода и локализован в конкретных участках программы, а не спрятан внутри большого `unsafe`-класса.
Пока эта модель находится в preview и может измениться до стабильного выпуска C# 15.double небольшие ошибки округления постепенно накапливаются. Особенно плохо, когда рядом оказываются очень большие и очень маленькие числа.
Обычный вариант:
double sum = 0;
foreach (double value in values)
{
sum += value;
}
Более точный вариант:
public static double KahanSum(ReadOnlySpan<double> values)
{
double sum = 0;
double compensation = 0;
foreach (double value in values)
{
double adjusted = value - compensation;
double next = sum + adjusted;
compensation = (next - sum) - adjusted;
sum = next;
}
return sum;
}
Переменная compensation сохраняет часть числа, потерянную при округлении, и возвращает её в следующее сложение.
Использование:
double[] values = { 0.1, 0.2, 0.3, 0.4 };
double result = KahanSum(values);
Метод полезен для:
- научных расчётов;
- статистики и аналитики;
- обработки сигналов;
- симуляций;
- накопления миллионов небольших значений.
ReadOnlySpan<double> позволяет передавать массивы и участки памяти без дополнительных копирований.
Алгоритм требует нескольких дополнительных операций на каждом шаге, зато заметно уменьшает накопленную погрешность.
Для денежных расчётов по-прежнему лучше использовать decimal. А когда нужна скорость double и повышенная численная устойчивость – пригодится Kahan Summation.