В чем разница между middleware и фильтром в ASP.NET Core?

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

Ответ

Middleware и фильтры — это два разных уровня обработки HTTP-запроса в ASP.NET Core с разными областями ответственности.

Middleware

  • Уровень: Низкоуровневый HTTP-конвейер приложения. Работает с HttpContext.
  • Область видимости: Глобальная для всего приложения. Обрабатывает все запросы, проходящие через конвейер.
  • Жизненный цикл: Выполняется в строгом порядке регистрации в Program.cs. Может обработать запрос и завершить конвейер, не передавая управление следующему компоненту (например, UseAuthentication может вернуть 401).
  • Назначение: Логика, не зависящая от фреймворка MVC/Razor Pages: аутентификация, авторизация, статические файлы, кэширование, кастомная обработка заголовков, глобальная обработка ошибок.

Пример кастомного middleware для логирования:

public class LoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

    public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        _logger.LogInformation("Начало обработки запроса: {Path}", context.Request.Path);
        var sw = Stopwatch.StartNew();

        await _next(context); // Передача управления следующему middleware

        sw.Stop();
        _logger.LogInformation("Запрос {Path} обработан за {ElapsedMs} мс", context.Request.Path, sw.ElapsedMilliseconds);
    }
}
// Регистрация в Program.cs
app.UseMiddleware<LoggingMiddleware>();
// или app.Use(async (context, next) => { ... });

Фильтры (Filters)

  • Уровень: Высокоуровневый конвейер MVC (или Razor Pages/API). Работают в контексте MVC (ActionExecutingContext, ActionExecutedContext).
  • Область видимости: Могут быть глобальными, но чаще применяются к конкретным контроллерам или действиям (action methods) с помощью атрибутов.
  • Жизненный цикл: Выполняются в рамках конвейера MVC (после маршрутизации и привязки модели, но до/после выполнения кода действия). Имеют четкие этапы: Authorization -> Resource -> Action -> Exception -> Result.
  • Назначение: Логика, тесно связанная с MVC: валидация модели, авторизация на уровне действия, кэширование результатов действия, обработка исключений в действиях.

Пример фильтра для валидации модели:

public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            // Прерываем выполнение действия, если модель невалидна
            context.Result = new BadRequestObjectResult(context.ModelState);
        }
        base.OnActionExecuting(context);
    }
}
// Применение к действию
[HttpPost]
[ValidateModel] // Фильтр сработает перед вызовом метода Create
public IActionResult Create(Product product) { ... }

Ключевое отличие: Middleware — это фундамент конвейера запросов, не знающий о MVC. Фильтры — это надстройка внутри MVC-фреймворка, имеющая доступ к его контексту (модели, действиям, результатам). Используйте middleware для кросс-резающей логики всего приложения, а фильтры — для логики, специфичной для контроллеров и действий.