Middleware и DI

Тема дорожной карты · .NET / C# Developer

Middleware в ASP.NET Core — это конвейер обработчиков, через который проходит каждый HTTP-запрос на пути к контроллеру и обратно. Каждый middleware решает: обработать запрос самому, передать дальше через await next(), или прервать пайплайн. DI-контейнер (Microsoft.Extensions.DependencyInjection) — встроенная реализация Inversion of Control: сервисы регистрируются один раз в Program.cs, после чего инфраструктура подставляет их в конструкторы middleware, контроллеров и других сервисов.

Как это работает

Пайплайн middleware строится в Program.cs через расширения app.UseXxx(). Порядок критически важен: UseAuthentication() должен идти до UseAuthorization(), UseRouting() — до UseEndpoints(). Каждый middleware — это либо класс с методом Task InvokeAsync(HttpContext, RequestDelegate), либо лямбда через app.Use(async (ctx, next) => ...). DI работает в трёх scope-ах: Singleton (один на приложение), Scoped (один на HTTP-запрос), Transient (новый каждый раз). Регистрация — services.AddScoped<IFoo, Foo>(). Внедрение — через конструктор или (в middleware) через метод InvokeAsync.

Когда применять

Кастомный middleware пишут для cross-cutting concerns: логирование запросов, корреляционные ID, обработка специфичных error-ов, custom-auth поверх стандартного, rate-limiting, мониторинг latency. Если задача связана с одним endpoint — используйте action filter, не middleware. DI применяется всегда — это базовый механизм передачи зависимостей в ASP.NET Core, прямые new Foo() или статика — антипаттерн.

Типичные ошибки

Неправильный порядок middleware — UseAuthentication после UseAuthorization ломает всё. Внедрение Scoped сервиса в Singleton (например, DbContext в фоновую службу) — DI выбросит ошибку или, что хуже, утечёт scope, и одна сессия пересекается с другой. Регистрация HttpClient как Singleton — приводит к DNS-кешированию и socket exhaustion на длинных uptime, используйте IHttpClientFactory со встроенными scoped-handlers. Хранение state в middleware — нарушает thread-safety, middleware должен быть stateless или использовать thread-local storage. Завершение пайплайна без await next() без явного намерения — ломает следующие middleware-ы.

Связанные понятия

Полезные ресурсы