Что такое Middleware в ASP.NET Core?

«Что такое Middleware в ASP.NET Core?» — вопрос из категории ASP.NET Core, который задают на 43% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Middleware — это компоненты, которые образуют конвейер обработки HTTP-запроса и ответа в приложении ASP.NET Core. Каждый middleware выполняет определенную задачу (логирование, аутентификация, обработка ошибок) и либо передает запрос дальше по цепочке, либо завершает обработку.

Ключевые принципы:

  • Конвейер: Middleware регистрируются в Program.cs (или Startup.Configure) в определенном порядке. Этот порядок критически важен.
  • Вызов next: Middleware решает, передать ли управление следующему компоненту в конвейере, вызвав next.Invoke().
  • Короткое замыкание: Middleware может не вызывать next, тем самым завершая конвейер и отправляя ответ клиенту (например, middleware для статических файлов или аутентификации при неудаче).

Типичная структура конвейера:

// Program.cs
var app = builder.Build();

// 1. Обработка исключений (должен быть первым, чтобы ловить ошибки со всех последующих этапов)
app.UseExceptionHandler("/Error");

// 2. Обслуживание статических файлов (CSS, JS, изображения)
app.UseStaticFiles();

// 3. Маршрутизация (определяет, какой контроллер/метод запустить)
app.UseRouting();

// 4. Аутентификация и авторизация
app.UseAuthentication();
app.UseAuthorization();

// 5. Конечные точки (запуск контроллеров, Minimal API)
app.MapControllers();

app.Run();

Создание собственного Middleware: Есть два основных способа:

  1. Класс Middleware:
    public class RequestTimingMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<RequestTimingMiddleware> _logger;
        public RequestTimingMiddleware(RequestDelegate next, ILogger<RequestTimingMiddleware> logger)
        {
            _next = next; _logger = logger;
        }
        public async Task InvokeAsync(HttpContext context)
        {
            var sw = Stopwatch.StartNew();
            await _next(context); // Передача управления дальше
            sw.Stop();
            _logger.LogInformation($"Запрос {context.Request.Path} выполнен за {sw.ElapsedMilliseconds} мс");
        }
    }
    // Регистрация: app.UseMiddleware<RequestTimingMiddleware>();
  2. Inline Middleware (удобно для простой логики):
    app.Use(async (context, next) =>
    {
        // Код до вызова next (обработка запроса)
        context.Response.Headers.Add("X-Request-Time", DateTime.UtcNow.ToString("o"));
        await next();
        // Код после вызова next (обработка ответа)
    });

Встроенные Middleware: UseHttpsRedirection, UseCors, UseResponseCompression, UseSession и многие другие.