Содержание
Именно с создания экземпляра этого класса начинается выполнение приложения. В этой части мы рассмотрим некоторые из свойств класса 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.
Что касается свойств класса 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 действует следующим образом:
- считывает значение переменной среды
ASPNETCORE_ENVIRONMENT
при вызове методаCreateBuilder()
и записывает полученное значение в свойствоEnvironmentName
. - Если значение
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 используется метод расширения для IWebHostBuilder
– ConfigureKestrel()
:
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.