Класс WebApplicationBuilder. Настройка приложения

Именно с создания экземпляра этого класса начинается выполнение приложения. В этой части мы рассмотрим некоторые из свойств класса WebApplicationBuilder.

Способы создания экземпляра WebApplicationBuilder

Экземпляр класса WebApplicationBuilder в проекте ASP.NET Core Web API необходим для выполнения следующих задач:

  • установка конфигурации приложения.
  • добавление и настройка сервисов, используемых в проекте, включая настройку поставщиков ведения журналов в приложении
  • общая конфигурация IHostBuilder и IWebHostBuilder, необходимых для создания хоста приложения.
  • начиная с .NET 8.0, WebApplicationBuilder также используется для настройки различных метрик приложения, необходимых для отслеживания работоспособности приложения.

По умолчанию переменная builder создается с использованием статического метода CreateBuilder() класса WebApplication.

var builder = WebApplication.CreateBuilder(args);

При этом, в метод передаются аргументы командной строки, которые могут содержать конфигурацию приложения. Вторая версия этого метода принимает в качестве параметра экземпляр класса WebApplicationOptions, содержащий основные настройки приложения. Например, мы можем переписать код создания экземпляра WebApplicationBuilder:

var builder = WebApplication.CreateBuilder(new WebApplicationOptions()
{
    Args = args,
    EnvironmentName = Environments.Development,
});

Здесь мы при создании переменной builder передали в метод экземпляр класса WebApplicationOptions, содержащего и аргументы командной строки и имя используемой среды выполнения – Development. На работу приложения такой вызов метода CreateBuilder() никак не повлияет.

Кроме метода CreateBuilder(), в .NET 8 также могут применяться новые статические методы класса WebApplication для создания экземпляра WebApplicationBuilder, представленные в таблице.

Метод Описание
CreateSlimBuilder() создает экземпляр WebApplicationBuilder с минимально необходимым набором настроек для запуска приложения. Так, в этом методе не настраиваются такие поставщики ведения журналов (логирования) как EventLog и EventSource. Также при вызове CreateSlimBuilder() не производится конфигурация сервера Kestrel для использования https и http/3.
CreateEmptyBuilder() создает WebApplicationBuilder без каких-либо настроек по умолчанию. Приложение будет использовать только те сервисы и настройки, которые будут явно настроены в приложении.

Оба этих метода, как и метод CreateBuilder() могут принимать в качестве параметров либо аргументы командной строки, либо экземпляр класса WebApplicationOptions. Потребность в этих методах возникла после того, как в ASP.NET Core появился собственный AOT (ahead-of-time) – компиляция приложения не в промежуточный, а сразу в машинный код. При использовании AOT необходимо добиваться того, чтобы приложение использовало в своей работе только те возможности и функции, которые действительно необходимы для нормальной работы и его размер был как можно меньше, поэтому методы CreateSlimBuilder() и CreateEmptyBuilder() и были добавлены в .NET 8.

Пока мы не достаточно разобрались с ASP.NET Core Web API, использовать эти методы не рекомендуется, чтобы случайно не нарушить работу всего приложения.

Что касается свойств класса WebApplicationBuilder, которые мы можем использовать для настройки нашего приложения, то они представлены в таблице.

Свойство Значение свойства Описание
Configuration ConfigurationManager Коллекция поставщиков конфигурации для создания приложения. Это свойство используется для добавления новых источников конфигурации приложения
Environment IWebHostEnvironment Предоставляет сведения об окружении приложения
Host ConfigureHostBuilder Объект IHostBuilder, который может использоваться для настройки свойств узла (хоста).
Logging ILoggingBuilder Коллекция поставщиков ведения журнала (логирования) приложения.
Services IServiceCollection Коллекция сервисов (служб), используемых приложением.
WebHost ConfigureWebHostBuilder Объект IWebHostBuilder для настройки отдельных свойств сервера
Metrics IMetricsBuilder Объект IMetricsBuilder, позволяющий включать различные метрики приложения и направлять их вывод (доступно, начиная с .NET 8)

Про такие свойства, как Configuration, Logging, Services и Metrics мы поговорим подробно в отдельно в других частях руководства.  Что касается других свойств, то рассмотрим некоторые из них более подробно.

Работа с окружением (свойство Environment)

Свойство Environment представлено объектом, реализующим интерфейс IWebHostEnvironment и представляет свойства и методы для взаимодействия приложения ASP.NET Core Web API со своим окружением

Тип Имя Значение Описание
Свойство ApplicationName string Имя приложения
Свойство ContentRootFileProvider IFileProvider Представляет собой реализацию интерфейса IFileProvider, которая может использоваться для работы с файлами в папке путь, к которой указан в свойстве ContentRootPath.
Свойство ContentRootPath string Абсолютный путь к папке, в которой находятся файлы содержимого приложения
Свойство EnvironmentName string Имя среды, в которой запущено приложение
Свойство WebRootFileProvider IFileProvider Представляет собой реализацию интерфейса IFileProvider, которая может использоваться для работы с файлами в папке, путь к которой указан в свойстве WebRootPath (по умолчанию это папка wwwroot)
Свойство WebRootPath string Абсолютный путь к папке, в которой содержатся файлы содержимого веб-приложения. По умолчанию используется вложенная папка wwwroot.
Метод расширения IsDevelopment() bool Проверяет, имеет ли текущая среда размещения имя Development.
Метод расширения IsEnvironment() bool Сравнивает имя текущей среды размещения с указанным значением
Метод расширения IsProduction() bool Проверяет, имеет ли текущая среда размещения имя Production.
Метод расширения IsStaging() bool Проверяет, имеет ли текущая среда размещения имя Staging.

Используя представленные в таблице свойства и методы расширения мы можем менять логику работы нашего приложения в зависимости от того, какая среда размещения используется. Например, изменить URL приложения, по которому оно будет доступно клиентам, или провести дополнительную настройку web-сервера и так далее.

Например, создадим новое приложение ASP.NET Core Web API, откроем файл Program.cs и изменим его код следующим образом:

var builder = WebApplication.CreateBuilder(args);

if (builder.Environment.IsEnvironment("Testing"))
{
    var color = Console.ForegroundColor;
    Console.ForegroundColor = ConsoleColor.Red;
    Console.WriteLine("Приложение находится в режиме тестирования!");
    Console.ForegroundColor = color;
}

builder.Services.AddControllers();
builder.Services.AddOpenApi();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseHttpsRedirection();
app.UseAuthorization();

app.MapControllers();

app.Run();

После того, как создается объект WebApplicationBuilder мы проверяем имеет ли среда размещения имя «Testing» и, если имеет, то в консоль будет выведено сообщение «Приложение находится в режиме тестирования». Измените в профиле запуска приложения, например, в «https» значение свойства ASPNETCORE_ENVIRONMENT на Testing и запустите приложение с этим профилем. Результат запуска приложения представлен на рисунке ниже

При определении имени среды окружения приложение ASP.NET Core действует следующим образом:

  1. считывает значение переменной среды ASPNETCORE_ENVIRONMENT при вызове метода CreateBuilder() и записывает полученное значение в свойство EnvironmentName.
  2. Если значение ASPNETCORE_ENVIRONMENT не было получено, то, по умолчанию, свойству EnvironmentName устанавливается значение Production

Так как файл launchSettings.json не разворачивается вместе с приложением (в папке с exe-файлом его нет), а переменная среды ASPNETCORE_ENVIRONMENT в Windows не была определена, то при запуске из проводника Windows для нашего приложения имя среды размещения будет автоматически установлено как Production и, исходя из этого значения в консоли уже не будет выводиться сообщение красным цветом, как было показано выше.

Таким образом, если нам необходимо, чтобы при запуске из проводника Windows имя среды размещения для нашего приложения отличалось от значения Production – нам необходимо задавать значение переменной ASPNETCORE_ENVIRONMENT, используя соответствующие инструменты операционной системы или задавать имя среды размещения непосредственно при вызове метода CreateBuilder(), например, так:

var builder = WebApplication.CreateBuilder(new WebApplicationOptions()
{
    EnvironmentName = "Testing"
});

Свойства ContentRootPath и WebRootPath

Также, стоит отметить, что из себя представляют свойства ContentRootPath и WebRootPath.

ContentRootPath — это свойство, которое указывает на папку в котором содержатся файлы, на которых строится приложение. Так, если вы запустите exe-файл приложения вне Visual Studio (например, из проводника Windows), то это свойство будет указывать на папку, в которой находится exe-файл приложения, json-файлы с настройками.

При запуске приложения в Visual Studio, например, в режиме отладки, ContentRootPath будет указывать на папку в которой находятся исходные файлы проекта (.cs, .cproj и т.д.).

WebRootPath — это свойство, которое всегда указывает на папку, в которой размещаются файлы web-приложения (html, js, css и т.д.). Обычно — это папка wwwroot (хотя, при необходимости, мы можем поменять это значение на любое другое). Так как для приложений Web API, по умолчанию, не требуется специальная папка для хранения файлов приложения, то в проекте папка wwwroot отсутствует, а значение свойства WebRootPath равно null.

При необходимости вы можете создать папку wwwroot, непосредственно, в обозревателе решений Visual Studio и эта папка будет распознана как место хранения файлов web-приложения, а переменной WebRootPath будет присвоено значение, соответствующее абсолютному пути к этой папке.

Настройка веб-сервера (свойство WebHost)

Свойство WebHost класса WebApplicationBuilder представлено объектом ConfigureWebHostBuilder, описание которого в C# выглядит следующим образом:

public sealed class ConfigureWebHostBuilder : IWebHostBuilder, ISupportsStartup

Для настройки веб-сервера приложения используются методы расширения для IWebHostBuilder. Здесь мы рассмотрим работу с веб-сервером – Kestrel, о котором мы уже имеем представление.

Конфигурация веб-сервера Kestrel (метод ConfigureKestrel и класс KestrelServerOptions)

Для того, чтобы изменить настройки сервера Kestrel используется метод расширения для IWebHostBuilderConfigureKestrel():

builder.WebHost.ConfigureKestrel(options =>
{
    //настройки веб-сервера
});

В качестве параметра, этот метод принимает делегат Action<KestrelServerOptions> в котором KestrelServerOptions – это класс, содержащий свойства и методы для конфигурирования сервера Kestrel. В таблице ниже представлены основные свойства класса KestrelServerOptions, которые мы можем использовать для настройки сервера.

Название Тип Описание
AddServerHeader Boolean Возвращает или задает значение, указывающее следует ли включать заголовок Server в каждый ответ
AllowResponseHeaderCompression Boolean Возвращает или задает значение, определяющее, разрешено ли динамическое сжатие заголовков ответов.
AllowSynchronousIO Boolean Возвращает или задает значение, определяющее, разрешены ли синхронные операции ввода-вывода для свойства Request.Body и Response.Body контекста запроса
Limits KestrelServerLimits Предоставляет доступ к параметрам ограничения запросов.

Например, отключим отправку заголовка Server в ответах:

builder.WebHost.ConfigureKestrel(options =>
{
     options.AddServerHeader = false;
});

По умолчанию этот заголовок включается в каждый ответ и, если мы используем для тестирования API http-файлы, то мы можем посмотреть этот заголовок

Указанная выше настройка приведет к тому, что в ответе этот заголовок будет отсутствовать и клиент уже не сможет просто так идентифицировать сервер, который отправляет ответ. Отдельно обратим внимание на свойство KestrelServerOptions.Limits. Это свойство представлено классом KestrelServerLimits и предоставляет доступ к установлению параметров ограничений запросов. Основные свойства этого класса представлены в таблице

Название Тип Описание
Http2 Http2Limits Ограничения, применимые только к подключениям HTTP/2.
Http3 Http3Limits Ограничения, применимые только к подключениям HTTP/3.
KeepAliveTimeout TimeSpan Получает или задает время ожидания проверки на активность соединения. Значение по умолчанию — 130 секунд.
MaxConcurrentConnections Nullable<Int64> Возвращает или задает максимальное число открытых подключений. Если задано значение NULL, количество подключений не ограничено. Значение по умолчанию — NULL.
MaxConcurrentUpgradedConnections Nullable<Int64> Возвращает или задает максимальное количество открытых обновленных подключений. Если задано значение NULL, количество обновленных подключений не ограничено. Обновленное соединение — это подключение, которое было переключено с HTTP на другой протокол, например WebSockets. Значение по умолчанию — NULL.
MaxRequestBodySize Nullable<Int64> Возвращает или задает максимальный допустимый размер текста запроса в байтах. Если задано значение NULL, максимальный размер текста запроса не ограничен. Его можно переопределить для каждого запроса с помощью IHttpMaxRequestBodySizeFeature. По умолчанию — 30 000 000 байт, что составляет приблизительно 28,6 МБ.
MaxRequestBufferSize Nullable<Int64> Возвращает или задает максимальный размер буфера запросов. Значение по умолчанию — 1 048 576 байт (1 МБ).
MaxRequestHeaderCount Int32 Возвращает или задает максимально допустимое количество заголовков на один HTTP-запрос. Значение по умолчанию — 100.
MaxRequestHeadersTotalSize Int32 Возвращает или задает максимальный допустимый размер заголовков HTTP-запросов. Значение по умолчанию — 32 768 байт (32 КБ).
MaxRequestLineSize Int32 Возвращает или задает максимальный допустимый размер строки HTTP-запроса. Значение по умолчанию — 8 192 байта (8 КБ).
MaxResponseBufferSize Nullable<Int64> Возвращает или задает максимальный размер буфера для записи ответов. Значение по умолчанию — 65 536 байт (64 КБ).
MinRequestBodyDataRate MinDataRate Возвращает или задает минимальную скорость передачи данных текста запроса в байтах в секунду. Присвоение этому свойству значения NULL означает, что минимальная скорость передачи данных не должна применяться. Его можно переопределить для каждого запроса с помощью IHttpMinRequestBodyDataRateFeature. Значение по умолчанию — 240 байт в секунду с 5-секундным льготным периодом.
MinResponseDataRate MinDataRate Возвращает или задает минимальную скорость передачи данных ответа в байтах в секунду. Присвоение этому свойству значения NULL означает, что минимальная скорость передачи данных не должна быть принудительной. Его можно переопределить для каждого запроса с помощью IHttpMinResponseDataRateFeature. Значение по умолчанию — 240 байтов в секунду с 5-секундным льготным периодом.
RequestHeadersTimeout TimeSpan Возвращает или задает максимальное время, в течение которого сервер будет получать заголовки запросов. Значение по умолчанию — 30 секунд.

Как можно видеть, веб-сервер Kestrel достаточно гибкий и настроить его можно самым различным образом. Например, воспользуемся некоторыми из этих настроек в нашем приложении

builder.WebHost.ConfigureKestrel(options =>
{
    options.AddServerHeader = false;
    options.Limits.KeepAliveTimeout = TimeSpan.FromSeconds(50);
    options.Limits.MaxConcurrentConnections = 10;
    options.Limits.MinResponseDataRate = new Microsoft.AspNetCore.Server.Kestrel.Core.MinDataRate(100, TimeSpan.FromSeconds(3));
});

В последней строке мы определили минимальную скорость передачи данных ответа и время задержки применения MinDataRate, начиная с момента первого чтения или записи данных – тот самый льготный период, о котором идёт речь в описании свойства в таблице выше.

Настройка конечных точек Kestrel

Сочетание адреса и протокола определяет конечную точку. Как можно заметить, при создании нового приложения ASP.NET Core платформа самостоятельно назначат номера портов, по которым сервер прослушивает конечную точку. Для настройки конечных точек веб-сервера в ASP.NET Core предусмотрено несколько способов и эти способы мы так или иначе затронем, однако сейчас сосредоточимся только на двух из них – использовании методов класса KestrelServerOptions и метода расширения для IWebHostBuilder.

Использование метода UseUrls()

Самый простой способ определить конечные точки для веб-сервера – это воспользоваться методом расширения UseUrls(). Этот метод принимает в качестве параметра массив URL-адресов. Например, определим следующие URL для Kestrel:

builder.WebHost.UseUrls(["http://localhost", "https://localhost:7890"]);

Теперь API будет доступен по двум адресам, причем, при доступе по протоколу HTTP будет использоваться порт по умолчанию – 80. Также, мы можем настраивать конечные точки Kestrel, передавая необходимые параметры непосредственно при настройке веб-сервера.

Использование методов класса KestrelServerOptions

У класса KestrelServerOptions определен ряд методов, начинающихся со слова Listen и позволяющих настроить конечные точки для веб-сервера. Используя эти методы, мы можем определить конкретный IP-адрес, который необходимо прослушивать, группу адресов и т.д.). Ниже показан пример того, как настроить сервер Kestrel на прослушивание нескольких адресов

builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenLocalhost(80);
    options.ListenLocalhost(7890, config =>
    {
       config.UseHttps();
    });
});

Здесь мы дважды вызываем метод ListenLocalhost(), указывая тем самым, что прослушиваться будут адреса вида [scheme]://localhost:[port]

Первый вызов метода содержит один параметр – номер порта (порт по умолчанию, например, 0 указывать в этом методе нельзя). Таким образом, первый вызов ListenLocalhost() указывает, что доступ к API будет осуществляться c использованием конечной точки http://localhost:80.

Во втором вызове метода ListenLocalhost() мы уже использовали два параметра: первый параметр – порт, второй – делегат Action<ListenOptions> в котором мы указываем дополнительные опции для конечной точки, а именно, вызываем метод UseHttps(), определяющий, что Kestrel должен использовать HTTPS с сертификатом по умолчанию. В результате мы получаем вторую конечную точку – https://localhost:7890. Можно запустить приложение и убедиться, что настройки конечных точек применены.

Стоит обратить внимание, что вызовы методов вида ListenXXX перезаписывают значения, которые могут использоваться в файле launchSettings.json, а также значения, переданные с использованием метода UseUrls() о чем Вы увидите сообщение после запуска приложения в режиме отладки. С таким сообщением мы уже встречались, когда знакомились с сервером Kestrel. Таким образом, окончательная настройка сервера Kestrel в нашем приложении может выглядеть следующим образом:

builder.WebHost.ConfigureKestrel(options =>
{
     options.AddServerHeader = false;
     options.Limits.KeepAliveTimeout = TimeSpan.FromSeconds(50);
     options.Limits.MaxConcurrentConnections = 10;
     options.Limits.MinResponseDataRate = new MinDataRate(100, TimeSpan.FromSeconds(3));
     options.ListenLocalhost(80);
     options.ListenLocalhost(7890, config =>
     {
        config.UseHttps();
     });
});

Настройка хоста (свойство Host)

Свойство Host класса WebApplicationBuilder представлено объектом ConfigureHostBuilder и, по аналогии со свойством WebHost, может использоваться для настройки хоста приложения. Свойство Host отвечает за инициализацию конфигурации приложения, контейнера внедрения зависимостей (DI), системы ведения журнала и т.д. Большинство настроек хоста реализуются через другие свойства объекта WebApplicationBuilder, например, для настройки системы ведения журнала используется свойство Logging, однако, в качестве примера, можно привести следующий код настройки хоста приложения:

var builder = WebApplication.CreateSlimBuilder(args);

builder.Host.UseConsoleLifetime(options =>
{
    options.SuppressStatusMessages = true;
});
builder.Host.ConfigureLogging(logging =>logging.AddDebug());

После создания объекта builder мы вызываем метод UseConsoleLifetime в который передаем делегат Action<ConsoleLifetimeOptions> с настройками консоли. По умолчанию, когда мы запускаем приложение, то в консоль выводятся информационные сообщения – имя среды размещения, путь к файлам приложения и т. д. В примере мы отключаем вывод таких сообщений в консоль, присваивая свойству SuppressStatusMessages значение true. В итоге, после запуска приложения мы увидим в консоли только URL приложения:

Далее, мы настраиваем систему ведения журнала, добавляя новый провайдер – консоль отладки приложения:

builder.Host.ConfigureLogging(logging =>logging.AddDebug());

Теперь, если запустить приложение в режиме отладки, то информационное сообщение появится и в консоли приложения, и в окне «Вывод» Visual Studio

Что касается добавления нового провайдера ведения журнала с использованием способа, который продемонстрирован в примере выше, то сама Visual Studio предложит вам воспользоваться другим (более удобным и корректным) способом настройки ведения журнала, хотя и используемый нами способ будет работать.

Итого

Таким образом, используя WebApplicationBuilder мы можем настраивать веб-сервера, использовать имя среду выполнения для начальной настройки приложения, а также выполнять ряд других важных операций. И теперь мы можем перейти к рассмотрению работы с одним из важнейших свойств класса WebApplicationBuilder – свойству Services, которое предназначено для настройки сервисов в приложении ASP.NET Core Web API.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии