en
Feedback
Библиотека шарписта | C#, F#, .NET, ASP.NET

Библиотека шарписта | C#, F#, .NET, ASP.NET

Open in Telegram

Все самое полезное для C#-разработчика в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/b60af5a4 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead

Show more

📈 Analytical overview of Telegram channel Библиотека шарписта | C#, F#, .NET, ASP.NET

Channel Библиотека шарписта | C#, F#, .NET, ASP.NET (@csharpproglib) in the Russian language segment is an active participant. Currently, the community unites 21 865 subscribers, ranking 6 209 in the Technologies & Applications category and 30 824 in the Russia region.

📊 Audience metrics and dynamics

Since its creation on невідомо, the project has demonstrated rapid growth, gathering an audience of 21 865 subscribers.

According to the latest data from 11 June, 2026, the channel demonstrates stable activity. Although there has been a change in the number of participants by -95 over the last 30 days and by -6 over the last 24 hours, overall reach remains high.

  • Verification status: Not verified
  • Engagement rate (ER): The average audience engagement rate is 12.48%. Within the first 24 hours after publication, content typically collects 7.13% reactions from the total number of subscribers.
  • Post reach: On average, each post receives 2 729 views. Within the first day, a publication typically gains 1 560 views.
  • Reactions and interaction: The audience actively supports content: the average number of reactions per post is 9.
  • Thematic interests: Content is focused on key topics such as .net, шарписта, навигация, await, string.

📝 Description and content policy

The author describes the resource as a platform for expressing subjective opinions:
Все самое полезное для C#-разработчика в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/b60af5a4 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead

Thanks to the high frequency of updates (latest data received on 12 June, 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.

21 865
Subscribers
-624 hours
-237 days
-9530 days
Posts Archive
⭐️ .NET 11 Preview 4 Microsoft выпустили четвёртый превью .NET 11. Релиз затрагивает рантайм, SDK, библиотеки, ASP.NET Core,
⭐️ .NET 11 Preview 4 Microsoft выпустили четвёртый превью .NET 11. Релиз затрагивает рантайм, SDK, библиотеки, ASP.NET Core, MAUI, EF Core и C#. Process API наконец стал удобным System.Diagnostics.Process получил набор методов, которых не хватало годами. Раньше для простого «запустить процесс и прочитать stdout» приходилось вручную подписываться на OutputDataReceived, создавать TaskCompletionSource и следить за жизненным циклом. Теперь это одна строка. Process.RunAndCaptureTextAsync запускает процесс и возвращает stdout, stderr и exit code:
var result = await Process.RunAndCaptureTextAsync(
    "git", ["status", "--porcelain"]);

Console.WriteLine(result.StandardOutput);
Console.WriteLine($"exit code: {result.ExitStatus.ExitCode}");
Process.StartAndForget запускает дочерний процесс без ожидания. ProcessStartInfo.StartDetached отвязывает процесс от терминала, чтобы он жил после закрытия консоли. На Windows есть обратный вариант: KillOnParentExit убивает дочерний процесс, когда родительский завершается. ProcessStartInfo.InheritedHandles позволяет передать дочернему процессу только конкретные OS-хендлы вместо поведения «всё или ничего» через UseShellExecute = false. На Linux и macOS убрали лишние аллокации при запуске процессов. ProcessName и ToString больше не создают полный снапшот ProcessInfo, а формирование envp/argv обходится без промежуточных managed-строк. Span-based сжатие для Deflate, ZLib и GZip В System.IO.Compression добавили API на основе Span<byte> для Deflate, ZLib и GZip. По форме они повторяют BrotliEncoder/BrotliDecoder и Zstandard-примитивы. Можно сжимать и распаковывать буферы без создания Stream.
using ZLibEncoder encoder = new();
OperationStatus status = encoder.Compress(
    source, destination, out int bytesConsumed,
    out int bytesWritten, isFinalBlock: true);
Полезно для протокольных парсеров, лог-шипперов и middleware, которые и так работают со спанами. Hex-формат для float и double double, float и Half теперь умеют форматироваться и парситься в hex-представлении IEEE-754. Формат сохраняет каждый бит значения, что критично для golden-file тестов и интеропа с C/C++ printf("%a", ...).
double value = Math.PI;
string hex = value.ToString("X"); // "0X1.921FB54442D18P+1"
double round = double.Parse(hex, NumberStyles.HexFloat);
Console.WriteLine(round == value); // True
System.Text.Json теперь понимает F# discriminated unions Сериализатор научился работать с F# discriminated unions без кастомных конвертеров. Если у вас F#-типы на бэкенде и C#-консьюмеры, теперь всё работает из коробки. Source generator тоже подтянули: generic-обёртки аксессоров правильно прокидывают constraints от исходного типа, а для доступа к приватным членам используется [UnsafeAccessor] вместо рефлексии. Рантайм-библиотеки скомпилированы с runtime-async Стандартные библиотеки рантайма теперь собираются с включённым runtime-async. Это внутренняя оптимизация JIT, которая уменьшает overhead async/await на горячих путях. ASP.NET Core В генерируемые OpenAPI-документы добавили поддержку HTTP-метода QUERY (RFC 9110). Для Blazor появился атрибут SupplyParameterFromTempData и серверная пауза Blazor Server circuit. Вместе с SDK теперь идёт шаблон MCP Server, так что создать MCP-совместимый бэкенд можно через dotnet new. SDK   dotnet watch получил выбор устройства для .NET MAUI и мобильных проектов. Fish shell теперь поддерживает автодополнение наравне с Bash, Zsh и PowerShell. CLI-телеметрия переехала с Application Insights на OpenTelemetry. ➡️ Полный список изменений 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #async_news

🔥 Знакомьтесь с экспертом Proglib.academy: Эмиль Сатаев Эмиль — эксперт с 8-летним опытом в разработке, который специализиру
🔥 Знакомьтесь с экспертом Proglib.academy: Эмиль Сатаев Эмиль — эксперт с 8-летним опытом в разработке, который специализируется на внедрении LLM и агентных подходов в реальные коммерческие сервисы. Он точно знает, как проектировать архитектуру так, чтобы ИИ-функции работали стабильно в связке с внешними системами. 🏃‍♀️ Уже 14 мая Эмиль проведет открытый вебинар! Обсудим самую «больную» тему: «Почему AI-продукты на базе LLM ломаются и как сделать, чтобы работало». 🗓 Когда: 14 мая в 19:00 (Мск) Почему Эмиля стоит послушать: 🟣 8+ лет в разработке (Backend и Frontend)
Прошел путь от фулстека до Backend Platform Developer в SMIT.Studio.
🟣 Международный исследовательский опыт
Работал исследователем в Институте ИИ НИУ ВШЭ и в Национальном университете Сингапура (NUS).
🟣 Преподаватель-практик
Ведет семинары в НИУ ВШЭ, в том числе по проектированию и разработке агентских систем.
🟣 Мастер интеграции AI в Backend
Его главная суперсила — умение правильно встраивать LLM через API, выстраивать workflow и агентную логику в сложных распределенных системах.
🔗 Зарегистрироваться на вебинар

⭐️ Шаблоны проектов теперь работают из командной строки Microsoft выпустила набор open-source шаблонов для WinUI, которые поз
⭐️ Шаблоны проектов теперь работают из командной строки Microsoft выпустила набор open-source шаблонов для WinUI, которые позволяют создавать приложения через dotnet new без Visual Studio. Пока это preview, но уже можно пользоваться. Зачем это нужно Раньше для создания WinUI-приложения нужно было открывать Visual Studio и проходить через мастер создания проекта. Это неудобно, если вы работаете в VS Code, автоматизируете создание проектов через скрипты или просто хотите быстро собрать болванку приложения. Теперь всё делается одной командой в терминале. Как начать Устанавливаем шаблоны и создаём приложение:
dotnet new install Microsoft.WindowsAppSDK.WinUI.CSharp.Templates
dotnet new winui-navview -n MyApp
cd MyApp
dotnet run
dotnet run сразу собирает и запускает упакованное приложение с package identity. Не нужен ни Add-AppxPackage, ни ручная регистрация. Под капотом работает WinApp CLI из пакета Microsoft.Windows.SDK.BuildTools.WinApp. Какие шаблоны доступны Все шаблоны следуют Windows app silhouettes и Fluent Design. В комплекте обновлённая иконка приложения с поддержкой светлой и тёмной темы. • Шаблон Blank (dotnet new winui) создаёт чистый проект с современным title bar и Fluent-стилями из коробки. • Шаблон NavigationView (dotnet new winui-navview) даёт готовую структуру с боковой навигацией и несколькими страницами. Подходит для большинства приложений. • Шаблон TabView (dotnet new winui-tabview) генерирует интерфейс на вкладках с поддержкой добавления, удаления и перетаскивания табов. • Шаблон MVVM (dotnet new winui-mvvm) включает базовую структуру Model-View-ViewModel с рабочим примером на CommunityToolkit.MVVM. Помимо шаблонов проектов, есть item-шаблоны для добавления отдельных элементов в существующий проект. Например, чтобы добавить ContentDialog:
dotnet new winui -n MyApp
cd MyApp
dotnet new winui-dialog -n MyDialog
Посмотреть все доступные шаблоны можно командой:
dotnet new list winui
Что дальше Шаблоны появятся и в Visual Studio 2026. Пока можно ставить из CLI и использовать с любым редактором. Шаблоны в open-source, фидбек и контрибьюции принимаются на GitHub. ➡️ Источник 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view

👨‍💻 Управляем буферизацией результатов Когда вы используете AsParallel(), PLINQ по умолчанию буферизует результаты перед тем, как отдать их вызывающему коду. Для небольших коллекций это незаметно. На больших объёмах данных стратегия буферизации напрямую влияет на задержку и пропускную способность. Метод WithMergeOptions позволяет явно указать, как PLINQ собирает результаты из параллельных потоков. Как использовать:
var results = items
    .AsParallel()
    .WithMergeOptions(ParallelMergeOptions.NotBuffered)
    .Select(ProcessItem)
    .ToList();
Три режима работыAutoBuffered — режим по умолчанию. PLINQ сам выбирает размер буфера. Подходит для большинства сценариев, когда вы не думаете о задержке. • FullyBuffered — все результаты сначала собираются в памяти, потом отдаются целиком. Полезно, когда важен порядок или когда вы всё равно ждёте полного завершения (например, при сортировке). Даёт максимальную пропускную способность, но первый элемент вы получите только после обработки последнего. • NotBuffered — результаты отдаются по мере готовности, без накопления. Минимальная задержка до первого элемента. Хорош для стриминговых сценариев или когда нужно начать обработку результатов как можно раньше. Когда это пригодится Если вы обрабатываете тысячи элементов и хотите показывать прогресс в реальном времени, NotBuffered сократит время до первого результата. Если же вам нужен отсортированный вывод или полная выборка перед следующим шагом, FullyBuffered будет эффективнее. На маленьких коллекциях разница между режимами минимальна. Оптимизация имеет смысл, когда элементов много или обработка каждого занимает ощутимое время. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view

🧑‍💻 HTTP Referer в ASP.NET Core Когда пользователь переходит по ссылке, браузер автоматически добавляет к запросу заголовок Referer — адрес страницы, с которой произошёл переход. Это стандартный механизм веба, и он уже встроен в HTTP. Никаких query string добавлять не нужно. Как читать Referer на сервере В ASP.NET Core заголовок доступен через Request.Headers:
app.MapGet("/page", (HttpContext ctx) =>
{
    var referer = ctx.Request.Headers["Referer"].ToString();

    if (string.IsNullOrEmpty(referer))
        return Results.Ok("Прямой переход или Referer скрыт");

    return Results.Ok($"Пришли с: {referer}");
});
В контроллерах то же самое:
[HttpGet]
public IActionResult Index()
{
    var referer = Request.Headers["Referer"].ToString();
    // использование по необходимости
    return View();
}
Как управлять тем, что браузер отправляет За это отвечает заголовок Referrer-Policy. Он задаётся на сервере и говорит браузеру, сколько информации об источнике передавать при переходах. Основные значения: no-referrer — браузер не отправляет Referer вообще. origin — передаёт только домен без пути: https://example.com/ вместо https://example.com/some/page. strict-origin-when-cross-origin — полный URL при переходах в рамках одного домена, только origin при переходах на другой домен, ничего при переходе с HTTPS на HTTP. unsafe-url — всегда передаёт полный URL, включая path и query. Название говорит само за себя. Настройка в ASP.NET Core Через middleware:
app.Use(async (ctx, next) =>
{
    ctx.Response.Headers["Referrer-Policy"] = "strict-origin-when-cross-origin";
    await next();
});
Или через app.UseHsts() в связке с пакетом NWebsec.AspNetCore.Middleware:
app.UseReferrerPolicy(opts => opts.StrictOriginWhenCrossOrigin());
Когда Referer может отсутствовать Браузер не отправляет заголовок в нескольких случаях: прямой ввод URL, переход из локального файла, политика no-referrer на стороне отправителя, переход с HTTPS на HTTP. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #il_люминатор

🛠 C# для микроконтроллеров Написать прошивку для микроконтроллера на C — это нормально, но долго. Нужно управлять памятью вр
🛠 C# для микроконтроллеров Написать прошивку для микроконтроллера на C — это нормально, но долго. Нужно управлять памятью вручную, разбираться с регистрами, держать в голове особенности конкретного железа. .NET nanoFramework меняет этот сценарий: код пишется на C#, отлаживается в Visual Studio, а запускается прямо на MCU. Что это такое .NET nanoFramework это открытая платформа для запуска C#-кода на микроконтроллерах с ограниченными ресурсами. Это не эмуляция и не кросс-компиляция в C. Прошивка nanoFramework устанавливается на устройство, и уже она выполняет скомпилированный C#-код. Как выглядит код Пример мигания светодиодом на ESP32:
using System.Device.Gpio;
using System.Threading;

var gpio = new GpioController();
gpio.OpenPin(2, PinMode.Output);

while (true)
{
    gpio.Write(2, PinValue.High);
    Thread.Sleep(500);
    gpio.Write(2, PinValue.Low);
    Thread.Sleep(500);
}
API намеренно выровнено с .NET IoT, поэтому код, написанный для Raspberry Pi через System.Device.Gpio, во многом переносится на MCU без серьёзных правок. Инструментарий Работа идёт в Visual Studio с бесплатным расширением nanoFramework. Поддерживается полноценный отладчик прямо на железе: точки останова, пошаговое выполнение, просмотр переменных. Пакеты распространяются через NuGet. Где применяется Среди реальных кейсов — мониторинг нефтяных скважин, удалённое управление солнечными электростанциями, промышленные измерительные системы. ➡️ Репозиторий 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view

🤩 Copilot Studio перешёл на .NET 10 и стал быстрее Microsoft Copilot Studio обновил свой WebAssembly-движок с .NET 8 до .NET
🤩 Copilot Studio перешёл на .NET 10 и стал быстрее Microsoft Copilot Studio обновил свой WebAssembly-движок с .NET 8 до .NET 10. Что изменилось Сам переход свёлся к обновлению <TargetFramework> на net10.0 и проверке совместимости зависимостей. Но за этим стоят три заметных улучшения в .NET 10 для WASM. Раньше WASM-приложениям приходилось вручную переименовывать файлы с добавлением SHA256-хеша для сброса кэша. Команда Copilot Studio использовала для этого отдельный PowerShell-скрипт, который читал манифест blazor.boot.json и прогонял каждый файл. В .NET 10 fingerprint встроен в имена файлов при публикации, а проверка целостности работает из коробки через dotnet.js. Скрипт удалили, аргумент integrity в загрузчике ресурсов убрали. Если вы загружаете .NET WASM-рантайм внутри WebWorker, при инициализации укажите dotnetSidecar = true. После AOT-компиляции методов в WebAssembly исходный IL-код больше не нужен в рантайме. В .NET 8 эта настройка существовала, но была выключена. Теперь IL автоматически вырезается из опубликованных сборок. Выигрыш в рантайме перекрывает рост размера пакета. Холодный запуск стал быстрее примерно на 20%. Повторные вызовы ускорились на ~5%. Больше всего выигрывают сложные агенты с большим объёмом AOT-кода. Как обновиться Обновите <TargetFramework> на net10.0 и подтяните свежие версии пакетов Microsoft.AspNetCore.*, Microsoft.Extensions.* и System.*. Если у вас были скрипты для переименования ресурсов или ручная проверка integrity, их можно удалить. Для автоматизации миграции Microsoft предлагает GitHub Copilot app modernization for .NET, который анализирует решение, планирует апгрейд и применяет изменения. ➡️ Блог разработчиков 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #async_news

📰 Второй майский дайджест Напоминаем, завтра выходной! — Кандидатов мало, а собесы становятся сложнее — Windows против други
📰 Второй майский дайджест Напоминаем, завтра выходной! — Кандидатов мало, а собесы становятся сложнееWindows против других ИИ Google Chrome автоматически загружает локальную модель Gemini Nano весом 4 ГБ без согласия пользователя, а ручное удаление файла приводит к повторной закачке. Заблокировать это можно через реестр Windows 11. Майкрософт делают упор на ИИ: — Строим AI-агентов на .NETAI-агенты в отказоустойчивом пайплайне на .NET 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #async_news

👨‍💻 Обработка исключений в AsParallel() Когда задачи выполняются параллельно и часть из них падает с ошибкой, .NET не бросает одно исключение. Вместо этого все ошибки собираются в AggregateException. Если не обработать его правильно, приложение просто упадёт, а вы потеряете детали о каждой конкретной ошибке. AggregateException содержит коллекцию InnerExceptions, где хранится каждое исключение из параллельного потока. Перебирая их в catch, мы получаем полный список того, что пошло не так, и можем реагировать на каждый случай отдельно. Вот как это выглядит:
try
{
    var results = items
        .AsParallel()
        .Select(item =>
        {
            if (item == null)
                throw new InvalidOperationException("Item is null");

            return ProcessItem(item);
        })
        .ToList();
}
catch (AggregateException ae)
{
    foreach (var ex in ae.InnerExceptions)
    {
        Console.WriteLine($"Handled: {ex.Message}");
    }
}
Если в items окажется null, код не упадёт молча. Каждая ошибка будет поймана и выведена отдельно. Используйте этот подход всегда, когда логика внутри AsParallel() может выбросить исключение. Это особенно актуально при работе с внешними данными, файлами или сетевыми вызовами, где ошибки непредсказуемы. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view

🗓 14 мая в 19:00 (Мск) встречаемся в онлайне. Тема: Почему AI-продукты на базе LLM ломаются и как сделать, чтобы работало. В кружке выше Эмиль Сатаев рассказал, какие именно проблемы с LLM в проде будем разбирать. Что в программе:
- Разберем реальные кейсы стартапов и ограничения LLM. - Обсудим рабочие архитектуры: RAG, human-in-the-loop, контроль качества. - Ответим на ваши вопросы и разберем кейсы участников.
🎁 Бонусы: в конце вебинара подарим промокод на скидку 10.000 ₽ на курсы и разыграем подписки на полезные AI-сервисы. 👉 Зарегистрироваться на вебинар

🔥 Вопрос с собеса Представьте: продакшн .NET Core сервис под высокой нагрузкой. Задержки растут, потоки блокируются, DBA смо
🔥 Вопрос с собеса Представьте: продакшн .NET Core сервис под высокой нагрузкой. Задержки растут, потоки блокируются, DBA смотрит на вас с подозрением. БД вроде бы ни при чём.. или всё же при чём? Что вы будете делать? Если знаете — пишите в комментариях 👇 Если хотите проверить себя — ответ уже ждёт вас здесь 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #dotnet_challenge

📎 async void: почему это почти всегда плохая идея Методы async void в C# выглядят безобидно, но скрывают ловушку. Если внутри такого метода возникнет исключение, поймать его стандартными средствами не получится. Оно просто вылетит в поток синхронизации и, скорее всего, уронит приложение. Почему вообще существует async void? Всё просто: обработчики событий по соглашению возвращают void. Без поддержки async void нельзя было бы использовать async/await внутри них. Это единственный законный случай. Официальное правило звучит так: async void допустим только как обработчик события, и такой метод не должен бросать исключения. Правильный обработчик выглядит примерно так:
private async void Button_Click(object sender, EventArgs e)
{
    try
    {
        await DoSomethingAsync();
    }
    catch (Exception ex)
    {
        // обрабатываем ошибку здесь, не даём ей вылететь наружу
        MessageBox.Show(ex.Message);
    }
}
Всё остальное — async Task или async Task<T>. Это позволяет нормально ловить исключения, ждать завершения и тестировать метод. Если видите async void не в обработчике, это сигнал для ревью. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view

🤩 Именованные поля в кортежах C# Иногда нужно вернуть из метода два-три значения или временно сгруппировать данные. Создават
🤩 Именованные поля в кортежах C# Иногда нужно вернуть из метода два-три значения или временно сгруппировать данные. Создавать для этого отдельный класс — лишняя работа. В C# 7+ есть кортежи с именованными полями, и они закрывают эту задачу. Как это выглядит Самый простой пример:
var user = (Name: "John", Age: 25);
Console.WriteLine(user.Name); // John
Console.WriteLine(user.Age);  // 25
Никакого класса, никакой модели. Просто структура с именами прямо там, где она нужна. Где это помогает Чаще всего кортежи с именами используют в возвращаемых значениях методов. Вместо того чтобы создавать out-параметры или отдельный DTO, можно сделать так:
public (string Name, bool IsValid) Validate(string input)
{
    var isValid = !string.IsNullOrWhiteSpace(input);
    return (input.Trim(), isValid);
}

var result = Validate("  John  ");
Console.WriteLine(result.Name);    // John
Console.WriteLine(result.IsValid); // True
Читаемость не хуже, чем у класса, а кода меньше. Деконструкция Кортеж можно сразу разложить по переменным:
var (name, isValid) = Validate("  John  ");
Console.WriteLine(name);    // John
Console.WriteLine(isValid); // True
Это удобно, если дальше в коде поля используются отдельно, а сам кортеж не нужен. Когда кортеж не подходит Кортежи хороши для локального использования и возвращаемых значений. Но если структура данных: - передаётся между слоями приложения - сериализуется в JSON или хранится в базе - используется более чем в двух-трёх местах Тогда лучше создать полноценный класс или record. Кортеж не несёт никакой доменной семантики — это просто набор значений. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view

😎 AI-агенты в отказоустойчивом пайплайне на .NET Microsoft Agent Framework получил поддержку устойчивых воркфлоу. Теперь можно описать пайплайн из нескольких AI-агентов один раз и запустить его как в памяти процесса, так и на Azure Functions с автомасштабированием и отказоустойчивостью. Что было до этого Если в многошаговом пайплайне процесс падал или перезапускался, всё состояние терялось. Для долгоживущих задач это критично: агент может работать минуты или часы, и потерять прогресс на середине — дорого. Что делает MAF Workflows Фреймворк позволяет описать шаги как Executor<TInput, TOutput>, соединить их в граф через WorkflowBuilder и выбрать способ запуска, не меняя определение воркфлоу. Поддерживаются паттерны: - последовательные цепочки - параллельный fan-out / fan-in - условный роутинг (AddSwitch) - человек в петле (human-in-the-loop через RequestPort) - вложенные воркфлоу как sub-orchestrations Как это работает Описываем шаги:
internal sealed class OrderLookup()
    : Executor<OrderCancelRequest, Order>("OrderLookup")
{
    public override async ValueTask<Order> HandleAsync(
        OrderCancelRequest message,
        IWorkflowContext context,
        CancellationToken cancellationToken = default)
    {
        await Task.Delay(100, cancellationToken);
        return new Order(Id: message.OrderId, ...);
    }
}
Собираем граф:
Workflow cancelOrder = new WorkflowBuilder(orderLookup)
    .WithName("CancelOrder")
    .AddEdge(orderLookup, orderCancel)
    .AddEdge(orderCancel, sendEmail)
    .Build();
Запускаем в памяти (для локальной разработки):
await using StreamingRun run =
    await InProcessExecution.RunStreamingAsync(cancelOrder, input: cancelRequest);

await foreach (WorkflowEvent evt in run.WatchStreamAsync())
{
    if (evt is ExecutorCompletedEvent completed)
        Console.WriteLine($"{completed.ExecutorId}: {completed.Data}");
}
Добавляем устойчивость Для production подключаем Microsoft.Agents.AI.DurableTask. Определение воркфлоу остаётся прежним, меняется только хостинг:
dotnet add package Microsoft.Agents.AI.DurableTask --prerelease
Запускаем локальный эмулятор DTS:
docker run -d --name dts-emulator \
  -p 8080:8080 -p 8082:8082 \
  mcr.microsoft.com/dts/dts-emulator:latest
Дашборд доступен на http://localhost:8082. Там видно хронологию шагов, входные и выходные данные каждого executor'а. Регистрируем воркфлоу с durable runtime:
IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.ConfigureDurableWorkflows(
            workflowOptions => workflowOptions.AddWorkflow(cancelOrder),
            workerBuilder: b => b.UseDurableTaskScheduler(dtsConnectionString),
            clientBuilder: b => b.UseDurableTaskScheduler(dtsConnectionString));
    })
    .Build();
Параллельные AI-агенты Агенты подключаются напрямую через AsAIAgent и запускаются параллельно. Если процесс упал в середине, завершённые агенты не перезапускаются:
AIAgent physicist = chatClient.AsAIAgent(
    "You are a physics expert. Be concise.", "Physicist");
AIAgent chemist = chatClient.AsAIAgent(
    "You are a chemistry expert. Be concise.", "Chemist");

Workflow workflow = new WorkflowBuilder(parseQuestion)
    .AddFanOutEdge(parseQuestion, [physicist, chemist])
    .AddFanInBarrierEdge([physicist, chemist], aggregator)
    .Build();
Одно определение воркфлоу работает везде: в памяти для разработки, с Durable Task для отказоустойчивости, на Azure Functions для serverless. Переключение между режимами не затрагивает код executor'ов. ➡️ Блог разработчиков 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #il_люминатор

✏️ AsOrdered — когда порядок элементов важен в PLINQ AsParallel() обрабатывает данные параллельно и не гарантирует, что резул
✏️ AsOrdered — когда порядок элементов важен в PLINQ AsParallel() обрабатывает данные параллельно и не гарантирует, что результат выйдет в том же порядке, что и входная последовательность. Если порядок важен, нужен AsOrdered(). Что делает AsOrdered Метод говорит PLINQ сохранять исходный порядок элементов в результирующей коллекции. Параллельная обработка при этом остаётся, но результат будет упорядочен так же, как входные данные. Зачем это нужно Есть случаи, когда порядок критичен — например, рендеринг элементов в UI или формирование отчёта, где строки должны идти в определённой последовательности. Без AsOrdered() результат непредсказуем. Пример использования:
var results = items
    .AsParallel()
    .AsOrdered()
    .Select(ProcessItem)
    .ToList();
PLINQ обработает элементы параллельно, но в results они окажутся в том же порядке, что и в items. Что учитывать AsOrdered() добавляет накладные расходы, ведь PLINQ вынужден отслеживать позиции элементов и собирать результат в нужном порядке. На больших объёмах данных это заметно. Поэтому используйте метод только там, где порядок действительно нужен, а не по умолчанию. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view

😕 Подборка вакансий для шарпистов .NET Developer (Backend) Middle — до 6,000 $, удалёнка C#/.NET-разработчик — удалёнка Разработчик С# (User Interface, WPF) — от 120 000 ₽, офис в Перми ➡️ Еще больше топовых вакансий — в нашем канале C# Jobs 🐸 Библиотека шарписта