Урок по треку C# и .NET 8 мин

ASP.NET Core

Конвейер middleware, DI и время жизни сервисов, контроллеры и minimal API, конфигурация.

На собесе по ASP.NET Core проверяют, понимаете ли вы путь запроса: конвейер middleware, DI, маршрутизацию, контроллеры или Minimal API, и где тут типичные ошибки.

Хост и Program.cs

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<AppDbContext>(o => o.UseNpgsql(builder.Configuration.GetConnectionString("Db")));
builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddControllers();

var app = builder.Build();
app.UseExceptionHandler();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.MapGet("/health", () => Results.Ok());
app.Run();

До Build() регистрируем сервисы, после него собираем конвейер.

Middleware

Конвейер это цепочка делегатов: каждый получает HttpContext и next. Код до await next() выполняется на пути запроса, после него на пути ответа. Любой middleware может не вызывать next и сам завершить запрос (короткое замыкание).

app.Use(async (ctx, next) =>
{
    var sw = Stopwatch.StartNew();
    await next();
    logger.LogInformation("{Path} за {Ms} мс", ctx.Request.Path, sw.ElapsedMilliseconds);
});

app.Run(handler) терминальный, app.Map("/path", ...) ветвит конвейер. Порядок критичен: обработчик исключений первым, аутентификация до авторизации, CORS до аутентификации.

Внедрение зависимостей

Время жизни:

  • Singleton: один на приложение, должен быть потокобезопасным.
  • Scoped: один на запрос (DbContext).
  • Transient: новый при каждом разрешении.

Правило: сервис не зависит от сервиса с более коротким временем жизни. Scoped внутри Singleton это captive dependency, в Development её ловит ValidateScopes. В синглтонах и BackgroundService scoped-сервисы берут через IServiceScopeFactory.CreateScope(). В .NET 8 есть keyed services для нескольких реализаций одного интерфейса.

Контроллеры и Minimal API

Контроллеры с [ApiController]: выводят источники параметров (сложный тип из тела), автоматически возвращают 400 при невалидной модели, есть фильтры MVC.

Minimal API: app.MapGet/MapPost, параметры из маршрута, запроса, тела и DI, MapGroup для общих префиксов и политик, фильтры конечных точек, TypedResults. Подходят и для больших сервисов, это вопрос стиля.

Конфигурация и Options

Источники накладываются: appsettings.json, appsettings.{Environment}.json, переменные окружения, секреты пользователя, аргументы командной строки. Типизированные настройки:

builder.Services.Configure<SmtpOptions>(builder.Configuration.GetSection("Smtp"));

IOptions<T> читает один раз, IOptionsSnapshot<T> на каждый запрос (scoped), IOptionsMonitor<T> отслеживает изменения и подходит для синглтонов.

HttpClient

Не создавайте new HttpClient() на каждый запрос: исчерпание сокетов. Используйте IHttpClientFactory (AddHttpClient<T>) или один долгоживущий клиент с PooledConnectionLifetime. Для повторов и таймаутов пакет Microsoft.Extensions.Http.Resilience (на основе Polly).

Фоновая работа

BackgroundService с ExecuteAsync(stoppingToken) для фоновой обработки. Очередь внутри процесса через Channel<T>, задания, которые должны пережить рестарт, через внешний брокер или outbox.

Безопасность

  • Аутентификация JWT: проверять подпись, exp, iss, aud, секрет хранить вне кода.
  • Авторизация: [Authorize], политики, проверка владельца ресурса (IDOR).
  • Пароли только хешами (PasswordHasher<T>).
  • Rate limiting (AddRateLimiter, .NET 7) на вход и дорогие эндпоинты.
  • CORS со списком доменов, а не AllowAnyOrigin.
  • Наружу DTO, а не сущности базы.

Обработка ошибок

AddProblemDetails и IExceptionHandler (.NET 8): исключения превращаются в ответ RFC 9457 без деталей стека.

Частые ошибки

  • Неправильный порядок middleware.
  • Scoped-зависимость в синглтоне.
  • new HttpClient() в каждом запросе.
  • Task.Run «в фоне» из контроллера.
  • Синхронные вызовы базы в обработчиках.

Что спросят на собесе

  • Как запрос проходит через конвейер middleware?
  • Чем отличаются Singleton, Scoped и Transient и что такое captive dependency?
  • Контроллеры или Minimal API?
  • Как правильно использовать HttpClient?
  • Как организовать фоновую обработку?

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.