Библиотека шарписта | C#, F#, .NET, ASP.NET
Все самое полезное для C#-разработчика в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/b60af5a4 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
إظهار المزيد📈 نظرة تحليلية على قناة تيليجرام Библиотека шарписта | C#, F#, .NET, ASP.NET
تُعد قناة Библиотека шарписта | C#, F#, .NET, ASP.NET (@csharpproglib) في القطاع اللغوي الروسية لاعباً نشطاً. يضم المجتمع حالياً 21 873 مشتركاً، محتلاً المرتبة 6 218 في فئة التكنولوجيات والتطبيقات والمرتبة 30 852 في منطقة روسيا.
📊 مؤشرات الجمهور والحراك
منذ تأسيسه في невідомо، حقق المشروع نمواً سريعاً وجمع 21 873 مشتركاً.
بحسب آخر البيانات بتاريخ 09 يونيو, 2026، تحافظ القناة على نشاط مستقر. خلال آخر 30 يوماً تغيّر عدد الأعضاء بمقدار -88، وفي آخر 24 ساعة بمقدار -7، مع بقاء الوصول العام مرتفعاً.
- حالة التحقق: غير موثّقة
- معدل التفاعل (ER): يبلغ متوسط تفاعل الجمهور 11.86%. وخلال أول 24 ساعة من النشر يحصد المحتوى عادةً 7.09% من ردود الفعل نسبةً إلى إجمالي المشتركين.
- وصول المنشورات: يحصل كل منشور على متوسط 2 594 مشاهدة. وخلال اليوم الأول يجمع عادةً 1 550 مشاهدة.
- التفاعلات والاستجابة: يتفاعل الجمهور بانتظام؛ متوسط التفاعلات لكل منشور يبلغ 9.
- الاهتمامات الموضوعية: يركز المحتوى على مواضيع رئيسية مثل .net, шарписта, навигация, await, string.
📝 الوصف وسياسة المحتوى
يصف المؤلف القناة بأنها مساحة للتعبير عن الآراء الذاتية:
“Все самое полезное для C#-разработчика в одном канале.
По рекламе: @proglib_adv
Учиться у нас: https://proglib.io/w/b60af5a4
Для обратной связи: @proglibrary_feeedback_bot
РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead”
بفضل وتيرة التحديث المرتفعة (أحدث البيانات بتاريخ 10 يونيو, 2026) تحافظ القناة على حداثتها ومستوى وصول مرتفع. وتُظهر التحليلات تفاعلاً نشطاً من الجمهور، ما يجعلها نقطة تأثير مهمة ضمن فئة التكنولوجيات والتطبيقات.
async/await убрали эту сложность.
Что происходит внутри
Компилятор превращает каждый async-метод в конечный автомат. Вот простой пример:
public static async Task SimpleBodyAsync() {
Console.WriteLine("Hello, Async World!");
}
После компиляции это превращается примерно в:
public static Task SimpleBodyAsync() {
var d = new <SimpleBodyAsync>d__0();
d.<>t__builder = AsyncTaskMethodBuilder.Create();
d.MoveNext();
return d.<>t__builder.Task;
}
Плюс отдельная struct с методом MoveNext, блоком try/catch и полями для хранения состояния. JIT не сможет встроить такой метод по месту вызова. Появляются издержки на вызов методов инфраструктуры SetResult, SetException и запись в поля конечного автомата.
Когда async лишний
Если метод всегда выполняется синхронно, оборачивать его в async нет смысла. Тауб приводит пример MemoryStream.ReadAsync: чтение из памяти и без того быстрое, и каждый вызов будет создавать новый объект Task<int> просто чтобы вернуть число.
Решение: возвращать кешированный результат вручную.
private Task<int> m_lastTask;
public override Task<int> ReadAsync(
byte[] buffer, int offset, int count,
CancellationToken cancellationToken)
{
int numRead = this.Read(buffer, offset, count);
return m_lastTask != null && numRead == m_lastTask.Result
? m_lastTask
: (m_lastTask = Task.FromResult(numRead));
}
Это позволяет при повторяющихся вызовах с одним и тем же результатом не создавать новые объекты совсем.
SynchronizationContext и лишние переходы
По умолчанию await захватывает текущий SynchronizationContext и возвращает продолжение в него. Для UI-потока это удобно: не нужно вручную делать маршалинг. Но в библиотечном коде это создаёт лишние переходы между потоками.
Если из UI-потока запустить цикл копирования с await на каждой операции чтения и записи мегабайта данных, получится более 500 переходов из фоновых потоков обратно в UI-поток. Чтобы этого избежать, в библиотеках следует использовать ConfigureAwait(false):
while ((numRead = await source.ReadAsync(buffer, 0, buffer.Length)
.ConfigureAwait(false)) > 0)
{
await destination.WriteAsync(buffer, 0, numRead)
.ConfigureAwait(false);
}
Без ConfigureAwait(false) в библиотечном коде возможна и взаимоблокировка: если вызывающий код в UI-потоке зовёт t.Wait(), а продолжение пытается вернуться в тот же заблокированный поток, оба будут ждать друг друга бесконечно.
Локальные переменные и сбор мусора
Компилятор поднимает все локальные переменные асинхронного метода в поля конечного автомата, который упаковывается в кучу при первом реальном ожидании. На момент выхода статьи компиляторы поднимали иногда больше переменных, чем нужно: даже те, что после await уже не читались.
// Лишнее поле в конечном автомате
public static async Task FooAsync() {
var dto = DateTimeOffset.Now;
var dt = dto.DateTime;
await Task.Yield();
Console.WriteLine(dt);
}
// Лучше так:
public static async Task FooAsync() {
var dt = DateTimeOffset.Now.DateTime;
await Task.Yield();
Console.WriteLine(dt);
}
Чем больше объектов создаётся, тем чаще срабатывает сборщик мусора. Это влияет на всю систему, а не только на конкретный метод.
Меньше await — лучше
Каждое await-выражение несёт накладные расходы. Если нужно подождать несколько задач, лучше объединить их через Task.WhenAll, чем ждать по одной:
// Хуже: три отдельных await
int ra = await a;
int rb = await b;
int rc = await c;
// Лучше: одно await на все три
int[] results = await Task.WhenAll(a, b, c);
async/await упростил жизнь разработчикам, но не отменил необходимость понимать, что происходит внутри.
➡️ Блог разработчиков
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_viewКак эффективно управлять контекстным окном LLM в мультиагентных системах и не сливать бюджет на токеныЖдем вас сегодня в 19:00 по московскому времени. Не пропустите начало, будет много практики! 👉 Успей занять место
CreateUserRequest, передал его прямо в сервис, сервис вернул UserResponse обратно в контроллер. Выглядит просто. Но это ловушка.
REST DTO это контракт с клиентом. Сервисный слой это бизнес-логика. Это разные ответственности.
Пример плохого кода:
// REST DTO
public class CreateUserRequest
{
public string Email { get; set; }
public string Password { get; set; }
public string Role { get; set; } // "admin", "user"
}
// Контроллер передаёт REST DTO прямо в сервис
[HttpPost]
public async Task<IActionResult> Create(CreateUserRequest request)
{
var user = await _userService.CreateAsync(request); // не надо
return Ok(user);
}
// Сервис знает о REST DTO
public async Task<UserResponse> CreateAsync(CreateUserRequest request)
{
// бизнес-логика завязана на HTTP-контракт
}
Теперь представьте, что появился второй клиент. Он шлёт другой формат. Или вы хотите вызвать CreateAsync из фоновой задачи, где нет никакого HTTP-запроса. Приходится либо тащить ненужный DTO, либо переписывать сервис.
Ещё хуже поле Role в CreateUserRequest. Клиент сам указывает, кем хочет стать. Даже если оно не используется или перезаписывается далее, выглядит это не очень.
Как правильно
Каждый слой работает со своей моделью. Контроллер маппит входящий DTO в команду или модель сервисного слоя. Сервис возвращает доменный результат. Контроллер маппит его в ответный DTO:
// REST DTO — только для HTTP-слоя
public class CreateUserRequest
{
public string Email { get; set; }
public string Password { get; set; }
// Role здесь нет — клиент не решает
}
public class UserResponse
{
public Guid Id { get; set; }
public string Email { get; set; }
public string Role { get; set; }
}
// Сервисная модель — внутренний контракт
public class CreateUserCommand
{
public string Email { get; set; }
public string Password { get; set; }
public UserRole Role { get; set; } // enum, не строка
}
public class UserResult
{
public Guid Id { get; set; }
public string Email { get; set; }
public UserRole Role { get; set; }
}
// Контроллер — маппит и не лезет в логику
[HttpPost]
public async Task<IActionResult> Create(CreateUserRequest request)
{
var command = new CreateUserCommand
{
Email = request.Email,
Password = request.Password,
Role = UserRole.User // роль задаётся здесь, не клиентом
};
var result = await _userService.CreateAsync(command);
var response = new UserResponse
{
Id = result.Id,
Email = result.Email,
Role = result.Role.ToString()
};
return Ok(response);
}
// Сервис — ничего не знает про HTTP
public async Task<UserResult> CreateAsync(CreateUserCommand command)
{
// чистая бизнес-логика
}
Почему это важно
Сервис перестаёт зависеть от формата HTTP-запроса. Его можно вызвать из воркера, gRPC-эндпоинта, теста без изменений.
Контракт с клиентом можно менять независимо от внутренней логики. Добавили поле в CreateUserRequest, сервис об этом не знает.
Валидация и маппинг живут в одном месте — в контроллере. Сервис получает уже проверенные данные в нужном формате.
Для маппинга удобно использовать AutoMapper или Mapster, но даже ручной маппинг лучше, чем слитые слои.
Граница между HTTP-слоем и бизнес-логикой — это не формальность. Это то, что позволяет менять одно, не трогая другое.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминатор
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминаторIStronglyTypedId<TValue> — теперь strongly-typed ID на основе record и ID, сгенерированные source-генератором через struct, работают под одним контрактом. Guards и DI-хелперы принимают оба варианта без дополнительного кода.
Добавили абстрактный record DomainEventBase. Раньше в каждом доменном событии нужно было вручную объявлять EventId и OccurredOnUtc. Теперь достаточно унаследоваться:
public sealed record OrderShippedEvent(OrderId OrderId) : DomainEventBase;
Сгенерированные struct-идентификаторы теперь реализуют IParsable<TSelf> и ISpanParsable<TSelf>. Это значит, что route-биндинг в ASP.NET Core minimal API работает из коробки без кастомных конверторов.
Source-генератор стал умнее: он проверяет во время компиляции, подключён ли EF Core, и генерирует ValueConverter<,> только если да. Лишний код в проект не попадает.
Что изменили
Все sub-пакеты переименованы — префикс Moongazing. убрали из NuGet PackageId:
Moongazing.OrionGuard.AspNetCore → OrionGuard.AspNetCore
Moongazing.OrionGuard.MediatR → OrionGuard.MediatR
Moongazing.OrionGuard.Generators → OrionGuard.Generators
И так далее для Swagger, OpenTelemetry, Blazor, Grpc, SignalR.
C#-пространства имён и структура папок не изменились. Существующие using-директивы продолжают работать.
Миграция с v6.1.0
В .csproj нужно обновить ссылки на пакеты: заменить Moongazing.OrionGuard.X на OrionGuard.X. Код трогать не нужно. Если хочется убрать бойлерплейт в доменных событиях — можно добавить : DomainEventBase, но это опционально.
➡️ Источник
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#async_newsControllers / Services / Models настолько привычна, что мы перестали её замечать. Но она главный источник боли по мере роста проекта.
Чтобы разобраться в одной фиче, приходится прыгать между тремя папками. Когда фича сложная код размазан по десятку файлов, и никто не держит в голове полную картину
Проблема: классические слои
Фича в типичном проекте выглядит так:
Controllers/ProductsController.cs Services/IProductService.cs Services/ProductService.cs Models/CreateProductRequest.csКаждый из файлов знает только о своём слое. Хотите понять одну операцию — обходите весь проект. Вертикальные срезы Принцип простой: код, который меняется вместе живёт вместе. Вместо горизонтальных слоёв на весь проект вертикальные срезы: один срез на одну фичу. Всё нужное в одной папке:
Features/
Products/
CreateProduct/
CreateProduct.cs ← всё здесь
Один файл содержит команду, валидацию и обработчик:
public static class CreateProduct
{
// Входные данные
public record Command(string Name, decimal Price) : IRequest<Guid>;
// Валидация
public class Validator : AbstractValidator<Command>
{
public Validator()
{
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.Price).GreaterThan(0);
}
}
// Логика
internal class Handler(AppDbContext db) : IRequestHandler<Command, Guid>
{
public async Task<Guid> Handle(Command req, CancellationToken ct)
{
var product = new Product { Name = req.Name, Price = req.Price };
db.Products.Add(product);
await db.SaveChangesAsync(ct);
return product.Id;
}
}
}
Пример использует MediatR для pipeline и Carter для регистрации. Они удобны, но не обязательны. Главное — положение кода
Что получаем
Высокая связность. Новый разработчик открывает одну папку и видит фичу целиком — от входа до выхода.
Низкое зацепление. Изменения в одном срезе не затрагивают другие. Никакого страха "а вдруг сломается что-то в другом месте".
Конец раздутым сервисам. IProductService неизбежно превращается в класс на тысячу строк с двадцатью ответственностями. Handler делает ровно одно дело.
А что с дублированием
Между срезами иногда появляется похожий код. Это нормально.
Цена небольшого дублирования несравнимо меньше, чем цена высокого зацепления и низкой связности, которые приносят горизонтальные слои. Долгосрочно это огромная победа.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_viewsudo apt update
sudo apt install dotnet-sdk-10.0
Проверить, что всё работает:
dotnet run - << 'EOF'
using System.Runtime.InteropServices;
Console.WriteLine($"Hello {RuntimeInformation.OSDescription} from .NET {RuntimeInformation.FrameworkDescription}");
EOF
Вывод будет примерно таким:
Hello Ubuntu Resolute Raccoon from .NET .NET 10.0.5Это так называемый file-based app. Он передаётся через
stdin напрямую в dotnet run. Стандартный unix-подход.
Контейнеры
Образы с тегом resolute уже доступны. Если вы использовали -noble, достаточно поменять суффикс:
sed -i "s/noble/resolute/g" Dockerfile.chiseled
После этого собрать и запустить с ограничениями ресурсов:
docker build --pull -t aspnetapp -f Dockerfile.chiseled .
docker run --rm -it -p 8000:8080 -m 50mb --cpus .5 aspnetapp
Chiseled-образы остались, ничего не убрали
Native AOT
Если нужен маленький бинарь с быстрым стартом — dotnet-sdk-aot-10.0 теперь в репозитории Ubuntu.
Установка:
apt install -y dotnet-sdk-aot-10.0 clang
Публикация простого приложения:
dotnet publish app.cs
Результат:
1.4M artifacts/app/app 3.0M artifacts/app/app.dbgЗапуск занял 3 миллисекунды. Для веб-сервиса с
PublishAot=true итоговый размер около 13 МБ вместе с метаданными System.Text.Json.
.NET 8 и 9 не входят в основной репозиторий Ubuntu 26.04, но доступны через отдельный PPA от Canonical:
apt install -y software-properties-common
add-apt-repository ppa:dotnet/backports
После подключения появятся пакеты dotnet-sdk-8.0, dotnet-sdk-9.0 и соответствующие aspnetcore-runtime-*. Поддержка там на уровне "best-effort", то есть официально, но без гарантий уровня LTS.
Что важно
Ubuntu 26.04 принёс три заметных изменения на уровне ОС:
• Linux 7.0 — команда .NET начнёт тестирование, как только получит VM.
• Постквантовая криптография — поддержка уже есть в .NET 10.
• Удаление cgroup v1. Переход на cgroup v2 в .NET сделали несколько лет назад, так что сломаться ничего не должно.
Если переходите на Ubuntu 26.04 в продакшне, то всё основное готово с первого дня.
➡️ Блог разработчиков
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#async_news// Копируется целиком при каждой передаче
public struct BigOrderStruct
{
public int Id;
public string Customer;
public decimal Total;
// ... ещё 12 полей
public List<Item> Items; // это уже ссылочный тип
}
Обратите внимание на List<Items>. Как только структура содержит ссылочные типы, часть преимуществ стека теряется, ведь ссылка всё равно уходит в кучу.
Для маленьких значений без ссылочных типов readonly record struct идеален:
public readonly record struct SmallOrderId(int Id);
Для всего остального readonly record class чаще выигрывает и по читаемости, и по производительности за счёт лучшего поведения кэша.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминаторСтатический конструктор — когда именно его вызывает рантаймВы не пишете
new MyClass(), не обращаетесь к объекту, не делаете вообще ничего явного. А он всё равно срабатывает.
➡️ Узнайте ответ
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#dotnet_challengeif (value == null) throw new ArgumentNullException(...) в каждом методе, кто-то тащит FluentValidation и настраивает его под свои нужды. OrionGuard предлагает ещё один вариант: fluent-интерфейс, поддержку ASP.NET Core, MediatR, Blazor, gRPC и SignalR. Всё в одной экосистеме.
Установка базового пакета:
dotnet add package OrionGuardПростая валидация выглядят так:
using Moongazing.OrionGuard.Core;
using Moongazing.OrionGuard.Extensions;
Ensure.That(email).NotNull().NotEmpty().Email();
Ensure.That(age).InRange(18, 120);
Если нужна производительность без аллокаций, то есть FastGuard на основе Span<T>:
FastGuard.NotNullOrEmpty(name, nameof(name));
FastGuard.Email(email, nameof(email));
Что внутри
Библиотека разбита на 9 пакетов. Каждый подключается отдельно.
OrionGuard — ядро. OrionGuard.AspNetCore — middleware, фильтры, интеграция с IOptions. OrionGuard.MediatR — автоматическая валидация в CQRS-пайплайне. OrionGuard.Generators — source-генераторы для компайл-тайм валидации без рефлексии. OrionGuard.Blazor — интеграция с EditForm. OrionGuard.Grpc и OrionGuard.SignalR — перехватчики для gRPC и SignalR.
Несколько конкретных примеров
Накопление ошибок без исключений:
var result = GuardResult.Combine(
Ensure.Accumulate(email, "Email").NotNull().Email().ToResult(),
Ensure.Accumulate(password, "Password").MinLength(8).ToResult()
);
if (result.IsInvalid)
return BadRequest(result.ToErrorDictionary());
Защита от SQL-инъекций и XSS:
userInput.AgainstSqlInjection(nameof(userInput));
userInput.AgainstXss(nameof(userInput));
filePath.AgainstPathTraversal(nameof(filePath));
Вложенная валидация с путями до поля:
var result = Validate.Nested(order)
.Property(o => o.OrderNumber, p => p.NotEmpty())
.Nested(o => o.Customer, customer => customer
.Property(c => c.Email, p => p.NotEmpty().Email())
.Nested(c => c.Address, address => address
.Property(a => a.ZipCode, p => p.NotEmpty())))
.Collection(o => o.Items, (item, _) => item
.Property(i => i.Quantity, p => p.GreaterThan(0)))
.ToResult();
// Ошибки будут выглядеть так: "Customer.Address.ZipCode", "Items[2].Quantity"
Динамические правила из JSON. Для случаев, когда правила хранятся в базе или конфиге:
var json = """
{
"Rules": [
{ "PropertyName": "Email", "RuleType": "Email" },
{ "PropertyName": "Age", "RuleType": "Range", "Parameters": { "Min": 18, "Max": 120 } }
]
}
""";
var validator = DynamicValidator.FromJson(json);
var result = validator.Validate(userDto);
Source-генератор для NativeAOT:
[GenerateValidator]
public sealed class CreateUserRequest
{
[NotNull, NotEmpty, Length(3, 50)]
public string Name { get; set; }
[NotNull, Email]
public string Email { get; set; }
}
// Валидатор генерируется на этапе компиляции — без рефлексии
var result = CreateUserRequestValidator.Validate(request);
Интеграция с ASP.NET Core:
// Program.cs
builder.Services.AddOrionGuardAspNetCore();
app.MapPost("/api/users", (CreateUserRequest req) => { ... })
.WithValidation<CreateUserRequest>();
Библиотека поддерживает 14 языков для сообщений об ошибках, включая русский. Есть слой совместимости с FluentValidation, миграция сводится к замене using. Все regex-паттерны генерируются через GeneratedRegex, FrozenSet используется для O(1)-поиска в security-паттернах. Последний релиз v6.2.0 вышел 22 апреля 2026.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_viewvar data = httpClient.GetStringAsync(url).Result; // блокирует поток
Task.Run(() => DoWork()).Wait(); // форсированная синхронизация
Эти вызовы берут асинхронную операцию и намеренно блокируют поток до её завершения. В результате поток занят, но не делает ничего полезного, а просто ждёт.
Попробуйте сделать так и замеряйте результат:
var data = await httpClient.GetStringAsync(url);
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминаторnode-gyp и конкретной версии Python на каждой машине разработчика. Для .NET-команды это лишняя зависимость, которую нужно поддерживать и в CI, и при онбординге новых участников.
Решение
Native AOT умеет компилировать .NET-код в нативную shared library с произвольными точками входа. Node.js аддоны требуют только одного: экспортированной функции napi_register_module_v1. Native AOT с этим справляется.
Как это работает
Аддон взаимодействует с Node.js через [N-API](https://nodejs.org/api/n-api.html) — стабильный C-совместимый интерфейс. Язык реализации значения не имеет, важно лишь соответствие сигнатурам.
Минимальный .csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<PublishAot>true</PublishAot>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
</Project>
PublishAot говорит SDK собрать нативную библиотеку при публикации. AllowUnsafeBlocks нужен из-за работы с указателями при интеропе с N-API.
Точка входа модуля:
[UnmanagedCallersOnly(
EntryPoint = "napi_register_module_v1",
CallConvs = [typeof(CallConvCdecl)])]
public static nint Init(nint env, nint exports)
{
Initialize();
RegisterFunction(env, exports, "readStringValue"u8, &ReadStringValue);
return exports;
}
Атрибут [UnmanagedCallersOnly] экспортирует метод с нужным именем и calling convention. Суффикс u8 создаёт ReadOnlySpan<byte> с UTF-8 строкой без аллокаций.
Вызов N-API из .NET
N-API функции экспортирует сам node.exe. Чтобы не линковаться с отдельной библиотекой, используется кастомный резолвер через NativeLibrary.SetDllImportResolver:
NativeLibrary.SetDllImportResolver(
Assembly.GetExecutingAssembly(),
(libraryName, assembly, searchPath) =>
libraryName is "node"
? NativeLibrary.GetMainProgramHandle()
: 0);
После этого P/Invoke с именем "node" будет резолвиться в хост-процесс:
[LibraryImport("node", EntryPoint = "napi_create_string_utf8")]
internal static partial Status CreateStringUtf8(
nint env, ReadOnlySpan<byte> str, nuint length, out nint result);
Пример экспортируемой функции
Функция читает значение из реестра Windows и возвращает его в JavaScript:
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
private static nint ReadStringValue(nint env, nint info)
{
try
{
var keyPath = GetStringArg(env, info, 0);
var valueName = GetStringArg(env, info, 1);
if (keyPath is null || valueName is null)
{
ThrowError(env, "Expected two string arguments: keyPath, valueName");
return 0;
}
using var key = Registry.CurrentUser.OpenSubKey(keyPath, writable: false);
return key?.GetValue(valueName) is string value
? CreateString(env, value)
: GetUndefined(env);
}
catch (Exception ex)
{
ThrowError(env, $"Registry read failed: {ex.Message}");
return 0;
}
}
Исключения нужно обязательно перехватывать: необработанное исключение в методе с [UnmanagedCallersOnly] крашит хост-процесс. ThrowError пробрасывает ошибку в JavaScript как стандартный Error.
Что в итоге
Команда убрала зависимость от Python и node-gyp. Теперь yarn install работает только с Node.js и .NET SDK, которые и так нужны для разработки. CI стал проще, онбординг быстрее.
Производительность сопоставима с C++-реализацией: Native AOT генерирует оптимизированный нативный код, а для задач типа доступа к реестру и маршалинга строк разницы на практике нет.
➡️ Источник
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_viewMicrosoft.AspNetCore.DataProtection, который попал в релиз вместе с плановым обновлением 10.0.6.
Что случилось
После выхода 10.0.6 пользователи начали сообщать, что расшифровка данных перестала работать. Microsoft изучила проблему и обнаружила, что регрессия также открывает уязвимость CVE-2026-40372.
Суть бага: управляемый энкриптор вычислял HMAC-тег не над теми байтами полезной нагрузки, а потом и вовсе выбрасывал результат. Это приводило к повышению привилегий. Затронуты версии Microsoft.AspNetCore.DataProtection от 10.0.0 до 10.0.6 включительно.
Кого это касается
Всех, кто использует ASP.NET Core Data Protection в приложениях на .NET 10. Это стандартный механизм защиты данных в ASP.NET Core — сессии, антифоргери-токены, куки и всё, что шифруется через IDataProtector.
Что делать
Обновить пакет Microsoft.AspNetCore.DataProtection до версии 10.0.7 как можно скорее:
dotnet add package Microsoft.AspNetCore.DataProtection --version 10.0.7
После обновления пакета пересобрать и перевыложить приложение. Проверить текущую версию SDK можно командой:
dotnet --info
➡️ Источник
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#async_newsКак эффективно управлять контекстным окном LLM в мультиагентных системах и не сливать бюджет на токеныВ кружке Кирилл рассказал, какие именно подходы будем разбирать. 👉 Занять место на вебинаре
متاح الآن! بحث تيليغرام 2025 — أهم رؤى العام 
