Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Примечание.
Это не последняя версия этой статьи. В текущем выпуске см. версию .NET 9 этой статьи.
Предупреждение
Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущем выпуске см. версию .NET 9 этой статьи.
Внимание
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В текущем выпуске см. версию .NET 9 этой статьи.
Авторы: Рик Андерсон (Rick Anderson) и Стив Смит (Steve Smith)
ПО промежуточного слоя — это программное обеспечение, выстраиваемое в виде конвейера приложения для обработки запросов и откликов. Каждый компонент:
- определяет, нужно ли передать запрос следующему компоненту в конвейере;
- может выполнять работу до и после следующего компонента в конвейере.
Для построения конвейера запросов используются делегаты запроса. Делегаты запросов обрабатывают каждый HTTP-запрос.
Делегаты запросов настраиваются с использованием методов расширения Run, Map и Use. Отдельный делегат запроса можно указать в виде встроенного анонимного метода (называемого посредником) либо определить в переиспользуемом классе. Эти многоразовые классы и встроенные анонимные методы являются промежуточным ПО или компонентами промежуточного слоя. Каждый компонент ПО промежуточного слоя в конвейере запросов отвечает за вызов следующего компонента в конвейере или замыкает конвейер. Когда промежуточный слой прерывает выполнение, он называется терминальным промежуточным слоем, так как препятствует обработке запроса другими промежуточными слоями.
Перенос модулей HTTP в ПО промежуточного слоя ASP.NET Core объясняет разницу между конвейерами запросов в ASP.NET Core и ASP.NET 4.x и предоставляет дополнительные примеры ПО промежуточного слоя.
Роль ПО промежуточного слоя по типу приложения
Blazor Web App, Razor Pages и MVC обрабатывают запросы браузера на сервере посредством промежуточного слоя. Инструкции, приведенные в этой статье, относятся к этим типам приложений.
Автономные Blazor WebAssembly приложения выполняются полностью на клиенте и не обрабатывают запросы с использованием промежуточного ПО. Руководство, приведенное в этой статье, не относится к автономным приложениям Blazor WebAssembly.
Анализ кода ПО промежуточного слоя
ASP.NET Core содержит множество анализаторов .NET Compiler Platform, проверяющих качество кода приложения. Дополнительные сведения см. в статье Анализ кода в приложениях ASP.NET Core.
Создайте middleware-конвейер с помощью WebApplication
Конвейер запросов ASP.NET Core состоит из последовательности делегатов запроса, вызываемых один за другим. На следующей схеме демонстрируется этот принцип. Поток выполнения показан черными стрелками.
Каждый из делегатов может выполнять операции до и после следующего делегата. Делегаты обработки исключений должны вызываться в начале конвейера, чтобы перехватывать исключения, возникающие на более поздних этапах.
Простейшее приложение ASP.NET Core задает один делегат запроса, обрабатывающий все запросы. В этом случае конвейер запросов как таковой отсутствует. Вместо этого в ответ на каждый HTTP-запрос вызывается одна анонимная функция.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello world!");
});
app.Run();
Несколько делегатов запроса можно соединить в цепочку с помощью Use. Параметр next
представляет следующий делегат в конвейере. Вы можете прервать выполнение конвейера, не вызывая функцию next
. Обычно действия можно выполнять как до, так и после next
делегата, как показано в этом примере:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
// Do work that can write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
app.Run();
Прерывание обработки конвейера запросов
Если делегат не передает запрос следующему делегату, это называется замыканием конвейера запросов. Короткое замыкание часто является предпочтительным, так как позволяет избежать ненужной работы. Например, промежуточное ПО для статических файлов может выступать в качестве завершающего промежуточного ПО, обрабатывая запрос к статическому файлу и прерывая остальную часть конвейера. Компоненты промежуточного слоя, добавленные в конвейер перед промежуточным слоем, завершающим обработку, продолжают обработку кода после своих команд next.Invoke
. Примите во внимание следующее предупреждение о попытке записи в ответ, который уже был отправлен.
Предупреждение
Не вызывайте next.Invoke
во время или после отправки ответа клиенту. После запуска HttpResponse, изменения приводят к исключению. Например, установка заголовков и кода состояния вызывает исключение после запуска ответа. Запись в тело отклика после вызова next
:
- Может вызвать нарушение протокола, например, запись данных сверх установленного
Content-Length
. - Может поврежден формат текста, например написание нижнего колонтитула HTML в CSS-файл.
HasStarted удобно использовать для обозначения того, были ли отправлены заголовки или выполнена запись в тело.
Дополнительные сведения см. в разделе Промежуточное программное обеспечение с коротким замыканием после маршрутизации.
Run
Делегаты
Делегаты Run не получают параметр next
. Первый делегат Run
всегда является конечным и завершает конвейер.
Run
— это соглашение. Некоторые компоненты промежуточного слоя могут предоставлять методы Run[Middleware]
, которые выполняются в конце конвейера:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
// Do work that can write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
app.Run();
Если вы хотите увидеть комментарии к коду, переведенные на языки, отличные от английского, сообщите нам на странице обсуждения этой проблемы на сайте GitHub.
В предыдущем примере делегат Run
записывает "Hello from 2nd delegate."
в ответ и завершает конвейер. Если добавить другой делегат Use
или Run
после делегата Run
, он не будет вызван.
Рекомендуется использовать перегрузку app.Use, требующую передачи контекста в следующий компонент.
Метод расширения без выделения app.Use:
- Требует передачи контекста в
next
. - Сохраняет два внутренних выделения на один запрос, которые требуются при другой перегрузке.
Дополнительные сведения см. здесь на GitHub.
Порядок ПО промежуточного слоя
На следующей схеме показан полный конвейер обработки запросов для приложений ASP.NET Core MVC и Razor Pages. Вы можете увидеть, как в стандартном приложении упорядочены существующие программы промежуточного слоя и где добавляются пользовательские программы промежуточного слоя. Вы можете полностью контролировать изменение порядка существующего ПО промежуточного слоя или внедрять новое пользовательское ПО промежуточного слоя для своих сценариев.
Промежуточное ПО конечной точки на предыдущей схеме выполняет конвейер фильтра для соответствующего типа приложения — MVC или страниц.
Промежуточное ПО Маршрутизации на вышеуказанной схеме размещено после Статических файлов. В таком порядке реализуются шаблоны проектов путем явного вызова app.UseRouting. Если вы не вызываете app.UseRouting
, то промежуточное ПО маршрутизации по умолчанию запускается в начале конвейера. Дополнительные сведения см. в разделе Маршрутизация.
Порядок добавления компонентов ПО промежуточного слоя в Program.cs
файл определяет порядок вызова компонентов ПО промежуточного слоя для запросов и обратного порядка ответа. Соблюдать этот порядок крайне важно для обеспечения безопасности, производительности и функциональности.
Следующий выделенный код в Program.cs
добавляет компоненты промежуточного слоя, связанные с безопасностью, в типично рекомендуемом порядке.
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebMiddleware.Data;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();
app.UseRouting();
// app.UseRateLimiter();
// app.UseRequestLocalization();
// app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();
app.MapRazorPages();
app.MapDefaultControllerRoute();
app.Run();
В предыдущем коде:
- ПО промежуточного слоя, которое не было добавлено при создании веб-приложения с учетными записями отдельных пользователей, деактивируется.
- Не каждое промежуточное программное обеспечение появляется в этом точном порядке, но многие из них соблюдают его. Например:
-
UseCors
,UseAuthentication
иUseAuthorization
должны присутствовать в указанном порядке. - Сейчас
UseCors
нужно использовать передUseResponseCaching
. Это требование объясняется в вопросе GitHub по адресу dotnet/aspnetcore #23218. -
UseRequestLocalization
должен отображаться перед любым промежуточным ПО, которое может проверить язык и региональные параметры запроса, напримерapp.UseStaticFiles()
. -
UseRateLimiter необходимо вызывать после
UseRouting
, когда используются API ограничения скорости для конкретных конечных точек. Например, если используется атрибут[EnableRateLimiting]
, необходимо вызватьUseRateLimiter
послеUseRouting
. При вызове только глобальных лимитаторовUseRateLimiter
можно вызвать раньшеUseRouting
.
-
В некоторых сценариях ПО промежуточного слоя имеет другой порядок. Например, порядок кэширования и сжатия зависит от сценария, и существует несколько допустимых вариантов такого порядка. Например:
app.UseResponseCaching();
app.UseResponseCompression();
С помощью приведенного выше кода можно снизить загрузку ЦП путем кэширования сжатого ответа, но при этом может быть выполнено кэширование нескольких представлений ресурса с помощью разных алгоритмов сжатия, таких как Gzip или Brotli.
В приведенном ниже порядке объединяются статические файлы, чтобы разрешить кэширование сжатых статических файлов.
app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();
Program.cs
Следующий код добавляет компоненты ПО промежуточного слоя для распространенных сценариев приложений:
- Обработка исключений и ошибок
- При запуске приложения в среде разработки:
- Промежуточное ПО для страницы исключений разработчика (UseDeveloperExceptionPage) сообщает об ошибках выполнения приложения.
- Промежуточное программное обеспечение страницы ошибок базы данных (UseDatabaseErrorPage) сообщает об ошибках времени выполнения базы данных.
- При запуске приложения в рабочей среде:
- Промежуточное ПО обработчика исключений (UseExceptionHandler) перехватывает исключения, возникшие в следующих промежуточных слоях.
- Промежуточный слой (middleware) протокола HSTS (HTTP Strict Transport Security) (UseHsts) добавляет заголовок
Strict-Transport-Security
.
- При запуске приложения в среде разработки:
- Промежуточное ПО для перенаправления HTTPS (UseHttpsRedirection) перенаправляет запросы с HTTP на HTTPS.
- Промежуточное ПО для статических файлов (UseStaticFiles) возвращает статические файлы и прерывает дальнейшую обработку запросов.
- Программное обеспечение Middleware Cookie (UseCookiePolicy) обеспечивает соответствие приложения требованиям Общего регламента по защите данных (GDPR) ЕС.
- Промежуточное ПО маршрутизации (UseRouting) для маршрутизации запросов.
- ПО промежуточного слоя проверки подлинности (UseAuthentication) пытается проверить подлинность пользователя, прежде чем предоставить ему доступ к защищенным ресурсам.
- ПО промежуточного слоя авторизации (UseAuthorization) разрешает пользователю доступ к защищенным ресурсам.
- Промежуточное ПО сеанса (UseSession) устанавливает и поддерживает состояние сеанса. Если в приложении используется состояние сеанса, вызовите промежуточное ПО сеанса после промежуточного ПО политики Cookie и до промежуточного ПО MVC.
- Промежуточное ПО маршрутизации конечных точек (UseEndpoints с MapRazorPages) для добавления конечных точек страниц Razor в конвейер запросов.
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();
В предыдущем примере кода каждый метод расширения промежуточного слоя предоставляется в WebApplicationBuilder с использованием пространства имен Microsoft.AspNetCore.Builder.
UseExceptionHandler — это первый компонент промежуточного слоя, добавленный в конвейер. Таким образом, промежуточное ПО для обработки исключений перехватывает все исключения, возникающие в последующих вызовах.
Промежуточный компонент статических файлов вызывается на ранних этапах конвейера. Это позволяет ему обрабатывать запросы и прекратить обработку, минуя остальные компоненты. Этот компонент статических файлов не выполняет проверки авторизации. Все файлы, обслуживаемые промежуточным программным обеспечением для статических файлов, включая те, что находятся в wwwroot, находятся в открытом доступе. Сведения о защите статических файлов см. в статье Статические файлы в ASP.NET Core.
Если запрос не обрабатывается компонентом промежуточного слоя для статических файлов, он передается в компонент промежуточного слоя для проверки подлинности (UseAuthentication), который выполняет проверку подлинности. Аутентификация не прерывает необработанные запросы. Хотя промежуточное программное обеспечение для аутентификации проверяет подлинность запросов, авторизация (и отклонение) выполняются только после того, как MVC выберет указанную страницу или контроллер MVC и action.
Следующий пример демонстрирует порядок работы компонентов промежуточного ПО, в котором запросы на статические файлы обрабатываются компонентом для статических файлов до компонента для сжатия ответов. Статические файлы не сжимаются при таком порядке промежуточного программного обеспечения. Ответы Razor Pages могут быть сжаты.
// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();
app.UseRouting();
app.UseResponseCompression();
app.MapRazorPages();
Дополнительные сведения о одностраничных приложениях см. в разделе "Общие сведения о одностраничных приложениях ( SPAs) в ASP.NET Core.
Порядок UseCors и UseStaticFiles
Порядок вызовов UseCors
и UseStaticFiles
зависит от приложения. Дополнительные сведения см. в разделе Порядок UseCors и UseStaticFiles.
Порядок промежуточного программного обеспечения для пересылаемых заголовков
Промежуточный слой для перенаправления заголовков должен выполняться перед другими промежуточными слоями. Такой порядок гарантирует, что промежуточное программное обеспечение, полагающееся на сведения о перенаправленных заголовках, может использовать значения заголовков для обработки. Чтобы запустить ПО перенаправления заголовков после ПО для диагностики и обработки ошибок, см. Порядок ПО перенаправления заголовков.
Разветвить конвейер промежуточного ПО
Расширения Map используются как условность для ветвления конвейера.
Map
разветвляет конвейер обработки запросов на основе совпадений с заданным путем запроса. Если путь запроса начинается с заданного пути, данная ветвь выполняется.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/map1", HandleMapTest1);
app.Map("/map2", HandleMapTest2);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleMapTest1(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
static void HandleMapTest2(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 2");
});
}
В таблице ниже приведены запросы и отклики http://localhost:1234
на базе предыдущего кода.
Запрос | Ответ |
---|---|
localhost:1234 | Привет от делегата, не относящегося к Map. |
localhost:1234/map1 | Тест карты 1 |
localhost:1234/map2 | Тест карты 2 |
localhost:1234/map3 | Привет от делегата, не относящегося к Map. |
Когда используется Map
, соответствующие сегменты путей удаляются из HttpRequest.Path
и добавляются к HttpRequest.PathBase
для каждого запроса.
Map
поддерживает вложение, например:
app.Map("/level1", level1App => {
level1App.Map("/level2a", level2AApp => {
// "/level1/level2a" processing
});
level1App.Map("/level2b", level2BApp => {
// "/level1/level2b" processing
});
});
Map
также может сопоставить несколько сегментов одновременно:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/map1/seg1", HandleMultiSeg);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleMultiSeg(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
MapWhen осуществляет ветвление конвейера запросов на основе результата заданного предиката. Любой предикат типа Func<HttpContext, bool>
можно использовать для сопоставления запросов с новой ветвью конвейера. В следующем примере предикат служит для определения наличия переменной строки запроса branch
.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleBranch(IApplicationBuilder app)
{
app.Run(async context =>
{
var branchVer = context.Request.Query["branch"];
await context.Response.WriteAsync($"Branch used = {branchVer}");
});
}
Ниже приведены запросы и отклики http://localhost:1234
на базе предыдущего кода.
Запрос | Ответ |
---|---|
localhost:1234 |
Hello from non-Map delegate. |
localhost:1234/?branch=main |
Branch used = main |
UseWhen также осуществляет ветвление конвейера запросов на основе результата заданного предиката. В отличие от MapWhen
, эта ветвь будет повторно присоединена к основной магистрали, если она не содержит промежуточный терминальный уровень.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
appBuilder => HandleBranchAndRejoin(appBuilder));
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
void HandleBranchAndRejoin(IApplicationBuilder app)
{
var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>();
app.Use(async (context, next) =>
{
var branchVer = context.Request.Query["branch"];
logger.LogInformation("Branch used = {branchVer}", branchVer);
// Do work that doesn't write to the Response.
await next();
// Do other work that doesn't write to the Response.
});
}
В предыдущем примере ответ Hello from non-Map delegate.
записывается для всех запросов. Если запрос включает переменную строки запроса branch
, ее значение регистрируется до того, как будет выполнено повторное объединение с основным конвейером.
Встроенное посредническое ПО
ASP.NET Core содержит следующие компоненты промежуточного слоя. В столбце Порядок указаны сведения о размещении ПО промежуточного слоя в конвейере обработки запросов и условия, в соответствии с которыми ПО промежуточного слоя может прервать обработку запроса. Если промежуточный слой замыкает конвейер обработки запроса и препятствует обработке запроса дальнейшими компонентами промежуточного слоя, он называется терминальным промежуточным слоем. Дополнительные сведения о коротком замыкании см. в разделе «Создание конвейера ПО промежуточного слоя с WebApplication».
посредническое программное обеспечение | Описание | Заказ |
---|---|---|
Защита от подделок | Предоставляет поддержку защиты от подделки запросов. | После проверки подлинности и авторизации, перед переходом к конечным точкам. |
Аутентификация | Обеспечивает поддержку проверки подлинности. | Перед тем, как потребуется HttpContext.User . Конечная точка для обратных вызовов OAuth. |
Авторизация | Обеспечивает поддержку авторизации. | Непосредственно после ПО промежуточного слоя для проверки подлинности. |
Политика Cookie | Обеспечивает отслеживание согласия пользователей на хранение личных сведений и соблюдение минимальных стандартов для полей cookie, таких как secure и SameSite . |
** Перед промежуточным ПО, которое выдает файлы cookie. Например: Authentication, Session, MVC (TempData). |
CORS | Настраивает общий доступ к ресурсам независимо от источника. | Ставится перед компонентами, использующими CORS.
UseCors сейчас нужно использовать перед UseResponseCaching из-за этой ошибки. |
DeveloperExceptionPage | Создает страницу со сведениями об ошибках, предназначенными для использования только в среде разработки. | Ставится перед компонентами, выдающими ошибки. Шаблоны проектов автоматически регистрируют это ПО промежуточного слоя в качестве первого в конвейере в среде разработки. |
Диагностика | Отдельное ПО промежуточного слоя, которое обеспечивает обработку исключений, предоставляет страницу исключений для разработчика, страницы состояния кода, веб-страницу по умолчанию для новых приложений. | Ставится перед компонентами, выдающими ошибки. Конечный пункт для обработки исключений или отображения веб-страницы по умолчанию для новых приложений. |
переадресованные заголовки | Пересылает заголовки прокси в текущий запрос. | Перед компонентами, использующими обновленные поля. Например: схема, узел, IP-адрес клиента, метод. |
Проверка работоспособности | Проверяет работоспособность приложения ASP.NET Core и его зависимостей, таких как проверка доступности базы данных. | Терминальным, если запрос соответствует терминальной точке проверки работоспособности. |
Распространение заголовков | Распространяет заголовки HTTP из входящего запроса на исходящие запросы HTTP-клиентов. | |
Ведение журнала HTTP | Регистрирует запросы и отклики HTTP. | В начале потока промежуточного программного обеспечения. |
Переопределение метода HTTP | Позволяет входящему запросу POST переопределить метод. | Ставится перед компонентами, использующими обновленный метод. |
Перенаправление HTTPS | Перенаправляет все запросы HTTP на HTTPS. | Ставится перед компонентами, использующими URL-адрес. |
Строгое обеспечение безопасности транспорта HTTP (HSTS) | ПО промежуточного слоя для повышения безопасности, которое добавляет специальный заголовок ответа. | Перед отправкой ответов и после компонентов, изменяющих запросы. Например: пересылка заголовков и переписывание URL. |
MVC; | Обрабатывает запросы с помощью MVC либо Razor Pages. | Является конечным, если запрос соответствует маршруту. |
OWIN | Взаимодействие с приложениями, серверами и промежуточным программным обеспечением на основе OWIN. | Конечный, если промежуточное программное обеспечение OWIN полностью обрабатывает запрос. |
Кэширование выходных данных | Предоставляет поддержку кэширования ответов на основе конфигурации. | Ставится перед компонентами, требующими кэширование.
UseRouting нужно использовать перед UseOutputCaching .
UseCORS нужно использовать перед UseOutputCaching . |
Кэширование ответов | Обеспечивает поддержку для кэширования откликов. Для этого требуется участие клиента в работе. Используйте кэширование выходных данных для полного управления сервером. | Ставится перед компонентами, требующими кэширование.
UseCORS нужно использовать перед UseResponseCaching . Обычно не подходит для приложений пользовательского интерфейса, таких как Pages, так как Razor браузеры обычно задают заголовки запросов, которые предотвращают кэширование.
Кэширование выходных данных обеспечивает преимущества приложений пользовательского интерфейса. |
Распаковка запросов | Обеспечивает поддержку распаковки запросов. | Ставится перед компонентами, которые считывают текст запроса. |
Сжатие откликов | Обеспечивает поддержку для сжатия откликов. | Ставится перед компонентами, требующими сжатие. |
Локализация запроса | Обеспечивает поддержку локализации. | Перед компонентами, чувствительными к локализации. Должно появляться после промежуточного ПО маршрутизации при использовании RouteDataRequestCultureProvider. |
Таймауты запросов | Предоставляет поддержку настройки времени ожидания запроса как в глобальном масштабе, так и для каждой конечной точки. |
UseRequestTimeouts должен прийти после UseExceptionHandler , UseDeveloperExceptionPage и UseRouting . |
Маршрутизация конечных точек | Определяет и ограничивает маршруты запросов. | Терминал для совпадающих маршрутов. |
Спа | Обрабатывает все запросы, начиная с этой точки в среде промежуточного слоя, возвращая страницу по умолчанию для одностраничного приложения (SPA) | В конце цепочки, чтобы другое ПО промежуточного слоя для обслуживания статических файлов, действий MVC и т. д. имело приоритет. |
Сеанс | Обеспечивает поддержку для управления пользовательскими сеансами. | Перед компонентами, которые требуют сеанса. |
Статические файлы | Обеспечивает поддержку для обработки статических файлов и просмотра каталогов. | Если запрос соответствует файлу, он является терминалом. |
Переопределение URL-адреса | Обеспечивает поддержку для переопределения URL-адресов и перенаправления запросов. | Ставится перед компонентами, использующими URL-адрес. |
W3CLogging | Создает журналы доступа к серверу в расширенном формате файла журнала W3C. | В начале потока промежуточного программного обеспечения. |
WebSockets | Обеспечивает поддержку протокола WebSockets. | Перед компонентами, которым нужно принимать запросы WebSocket. |
Дополнительные ресурсы
- Параметры времени существования и регистрации содержат полный пример посреднического ПО со службами, имеющими время существования scoped (с заданной областью), transient (временное) и singleton (одиночное).
- Написание пользовательского посредника ASP.NET Core
- Тестирование по промежуточному слоям ASP.NET Core
- Настройка gRPC-Web в ASP.NET Core
- Перенос модулей HTTP в ПО промежуточного слоя ASP.NET Core
- Запуск приложения в ASP.NET Core
- Функции запроса в ASP.NET Core
- Активация промежуточного ПО на основе фабрики в ASP.NET Core
- Активация ПО промежуточного слоя с помощью стороннего контейнера в ASP.NET Core
Авторы: Рик Андерсон (Rick Anderson) и Стив Смит (Steve Smith)
ПО промежуточного слоя — это программное обеспечение, выстраиваемое в виде конвейера приложения для обработки запросов и откликов. Каждый компонент:
- определяет, нужно ли передать запрос следующему компоненту в конвейере;
- может выполнять работу до и после следующего компонента в конвейере.
Для построения конвейера запросов используются делегаты запроса. Делегаты запросов обрабатывают каждый HTTP-запрос.
Делегаты запросов настраиваются с использованием методов расширения Run, Map и Use. Отдельный делегат запроса можно указать в виде встроенного анонимного метода (называемого посредником) либо определить в переиспользуемом классе. Эти многоразовые классы и встроенные анонимные методы являются промежуточным ПО или компонентами промежуточного слоя. Каждый компонент ПО промежуточного слоя в конвейере запросов отвечает за вызов следующего компонента в конвейере или замыкает конвейер. Когда промежуточный слой прерывает выполнение, он называется терминальным промежуточным слоем, так как препятствует обработке запроса другими промежуточными слоями.
Перенос модулей HTTP в ПО промежуточного слоя ASP.NET Core объясняет разницу между конвейерами запросов в ASP.NET Core и ASP.NET 4.x и предоставляет дополнительные примеры ПО промежуточного слоя.
Роль ПО промежуточного слоя по типу приложения
Razor Pages, MVC, Blazor Serverи серверный проект размещенного решения Blazor WebAssembly обрабатывают запросы браузера на сервере с использованием промежуточного слоя. Инструкции, приведенные в этой статье, относятся к этим типам приложений.
Автономные Blazor WebAssembly приложения выполняются полностью на клиенте и не обрабатывают запросы с использованием промежуточного ПО. Руководство, приведенное в этой статье, не относится к автономным приложениям Blazor WebAssembly.
Анализ кода ПО промежуточного слоя
ASP.NET Core содержит множество анализаторов .NET Compiler Platform, проверяющих качество кода приложения. Дополнительные сведения см. в статье Анализ кода в приложениях ASP.NET Core.
Создайте middleware-конвейер с помощью WebApplication
Конвейер запросов ASP.NET Core состоит из последовательности делегатов запроса, вызываемых один за другим. На следующей схеме демонстрируется этот принцип. Поток выполнения показан черными стрелками.
Каждый из делегатов может выполнять операции до и после следующего делегата. Делегаты обработки исключений должны вызываться в начале конвейера, чтобы перехватывать исключения, возникающие на более поздних этапах.
Простейшее приложение ASP.NET Core задает один делегат запроса, обрабатывающий все запросы. В этом случае конвейер запросов как таковой отсутствует. Вместо этого в ответ на каждый HTTP-запрос вызывается одна анонимная функция.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello world!");
});
app.Run();
Несколько делегатов запроса можно соединить в цепочку с помощью Use. Параметр next
представляет следующий делегат в конвейере. Вы можете прервать выполнение конвейера, не вызывая функцию next
. Обычно действия можно выполнять как до, так и после next
делегата, как показано в этом примере:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
// Do work that can write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
app.Run();
Если делегат не передает запрос следующему делегату, это называется замыканием конвейера запросов. Короткое замыкание часто является предпочтительным, так как позволяет избежать ненужной работы. Например, промежуточное ПО для статических файлов может выступать в качестве завершающего промежуточного ПО, обрабатывая запрос к статическому файлу и прерывая остальную часть конвейера. Компоненты промежуточного слоя, добавленные в конвейер перед промежуточным слоем, завершающим обработку, продолжают обработку кода после своих команд next.Invoke
. Примите во внимание следующее предупреждение о попытке записи в ответ, который уже был отправлен.
Предупреждение
Не вызывайте next.Invoke
после отправки отклика клиенту. Изменения HttpResponse после начала отправки ответа приведут к возникновению исключения. Например, при задании заголовков и кода состояния возникает исключение. Запись в тело отклика после вызова next
:
- может вызвать нарушение протокола, например, при записи более установленного значения
Content-Length
; - может привести к нарушению формата тела. например, при записи нижнего колонтитула HTML в CSS-файл.
HasStarted удобно использовать для обозначения того, были ли отправлены заголовки или выполнена запись в тело.
Делегаты Run не получают параметр next
. Первый делегат Run
всегда является конечным и завершает конвейер.
Run
— это соглашение. Некоторые компоненты промежуточного слоя могут предоставлять методы Run[Middleware]
, которые выполняются в конце конвейера:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
// Do work that can write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
app.Run();
Если вы хотите увидеть комментарии к коду, переведенные на языки, отличные от английского, сообщите нам на странице обсуждения этой проблемы на сайте GitHub.
В предыдущем примере делегат Run
записывает "Hello from 2nd delegate."
в ответ и завершает конвейер. Если добавить другой делегат Use
или Run
после делегата Run
, он не будет вызван.
Рекомендуется использовать перегрузку app.Use, требующую передачи контекста в следующий компонент.
Метод расширения без выделения app.Use:
- Требует передачи контекста в
next
. - Сохраняет два внутренних выделения на один запрос, которые требуются при другой перегрузке.
Дополнительные сведения см. здесь на GitHub.
Порядок ПО промежуточного слоя
На следующей схеме показан полный конвейер обработки запросов для приложений ASP.NET Core MVC и Razor Pages. Вы можете увидеть, как в стандартном приложении упорядочены существующие программы промежуточного слоя и где добавляются пользовательские программы промежуточного слоя. Вы можете полностью контролировать изменение порядка существующего ПО промежуточного слоя или внедрять новое пользовательское ПО промежуточного слоя для своих сценариев.
Промежуточное ПО конечной точки на предыдущей схеме выполняет конвейер фильтра для соответствующего типа приложения — MVC или страниц.
Промежуточное ПО Маршрутизации на вышеуказанной схеме размещено после Статических файлов. В таком порядке реализуются шаблоны проектов путем явного вызова app.UseRouting. Если вы не вызываете app.UseRouting
, то промежуточное ПО маршрутизации по умолчанию запускается в начале конвейера. Дополнительные сведения см. в разделе Маршрутизация.
Порядок добавления компонентов ПО промежуточного слоя в Program.cs
файл определяет порядок вызова компонентов ПО промежуточного слоя для запросов и обратного порядка ответа. Соблюдать этот порядок крайне важно для обеспечения безопасности, производительности и функциональности.
Следующий выделенный код в Program.cs
добавляет компоненты промежуточного слоя, связанные с безопасностью, в типично рекомендуемом порядке.
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebMiddleware.Data;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();
app.UseRouting();
// app.UseRateLimiter();
// app.UseRequestLocalization();
// app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();
app.MapRazorPages();
app.MapDefaultControllerRoute();
app.Run();
В предыдущем коде:
- ПО промежуточного слоя, которое не было добавлено при создании веб-приложения с учетными записями отдельных пользователей, деактивируется.
- Не каждое промежуточное программное обеспечение появляется в этом точном порядке, но многие из них соблюдают его. Например:
-
UseCors
,UseAuthentication
иUseAuthorization
должны присутствовать в указанном порядке. - Сейчас
UseCors
нужно использовать передUseResponseCaching
. Это требование объясняется в вопросе GitHub по адресу dotnet/aspnetcore #23218. -
UseRequestLocalization
должен отображаться перед любым промежуточным ПО, которое может проверить язык и региональные параметры запроса, напримерapp.UseStaticFiles()
. -
UseRateLimiter необходимо вызывать после
UseRouting
, когда используются API ограничения скорости для конкретных конечных точек. Например, если используется атрибут[EnableRateLimiting]
, необходимо вызватьUseRateLimiter
послеUseRouting
. При вызове только глобальных лимитаторовUseRateLimiter
можно вызвать раньшеUseRouting
.
-
В некоторых сценариях ПО промежуточного слоя имеет другой порядок. Например, порядок кэширования и сжатия зависит от сценария, и существует несколько допустимых вариантов такого порядка. Например:
app.UseResponseCaching();
app.UseResponseCompression();
С помощью приведенного выше кода можно снизить загрузку ЦП путем кэширования сжатого ответа, но при этом может быть выполнено кэширование нескольких представлений ресурса с помощью разных алгоритмов сжатия, таких как Gzip или Brotli.
В приведенном ниже порядке объединяются статические файлы, чтобы разрешить кэширование сжатых статических файлов.
app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();
Program.cs
Следующий код добавляет компоненты ПО промежуточного слоя для распространенных сценариев приложений:
- Обработка исключений и ошибок
- При запуске приложения в среде разработки:
- Промежуточное ПО для страницы исключений разработчика (UseDeveloperExceptionPage) сообщает об ошибках выполнения приложения.
- Промежуточное программное обеспечение страницы ошибок базы данных (UseDatabaseErrorPage) сообщает об ошибках времени выполнения базы данных.
- При запуске приложения в рабочей среде:
- Промежуточное ПО обработчика исключений (UseExceptionHandler) перехватывает исключения, возникшие в следующих промежуточных слоях.
- Промежуточный слой (middleware) протокола HSTS (HTTP Strict Transport Security) (UseHsts) добавляет заголовок
Strict-Transport-Security
.
- При запуске приложения в среде разработки:
- Промежуточное ПО для перенаправления HTTPS (UseHttpsRedirection) перенаправляет запросы с HTTP на HTTPS.
- Промежуточное ПО для статических файлов (UseStaticFiles) возвращает статические файлы и прерывает дальнейшую обработку запросов.
- Программное обеспечение Middleware Cookie (UseCookiePolicy) обеспечивает соответствие приложения требованиям Общего регламента по защите данных (GDPR) ЕС.
- Промежуточное ПО маршрутизации (UseRouting) для маршрутизации запросов.
- ПО промежуточного слоя проверки подлинности (UseAuthentication) пытается проверить подлинность пользователя, прежде чем предоставить ему доступ к защищенным ресурсам.
- ПО промежуточного слоя авторизации (UseAuthorization) разрешает пользователю доступ к защищенным ресурсам.
- Промежуточное ПО сеанса (UseSession) устанавливает и поддерживает состояние сеанса. Если в приложении используется состояние сеанса, вызовите промежуточное ПО сеанса после промежуточного ПО политики Cookie и до промежуточного ПО MVC.
- Промежуточное ПО маршрутизации конечных точек (UseEndpoints с MapRazorPages) для добавления конечных точек страниц Razor в конвейер запросов.
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();
В предыдущем примере кода каждый метод расширения промежуточного слоя предоставляется в WebApplicationBuilder с использованием пространства имен Microsoft.AspNetCore.Builder.
UseExceptionHandler — это первый компонент промежуточного слоя, добавленный в конвейер. Таким образом, промежуточное ПО для обработки исключений перехватывает все исключения, возникающие в последующих вызовах.
Промежуточный компонент статических файлов вызывается на ранних этапах конвейера. Это позволяет ему обрабатывать запросы и прекратить обработку, минуя остальные компоненты. Этот компонент статических файлов не выполняет проверки авторизации. Все файлы, обслуживаемые промежуточным программным обеспечением для статических файлов, включая те, что находятся в wwwroot, находятся в открытом доступе. Сведения о защите статических файлов см. в статье Статические файлы в ASP.NET Core.
Если запрос не обрабатывается компонентом промежуточного слоя для статических файлов, он передается в компонент промежуточного слоя для проверки подлинности (UseAuthentication), который выполняет проверку подлинности. Аутентификация не прерывает необработанные запросы. Хотя промежуточное программное обеспечение для аутентификации проверяет подлинность запросов, авторизация (и отклонение) выполняются только после того, как MVC выберет указанную страницу или контроллер MVC и action.
Следующий пример демонстрирует порядок работы компонентов промежуточного ПО, в котором запросы на статические файлы обрабатываются компонентом для статических файлов до компонента для сжатия ответов. Статические файлы не сжимаются при таком порядке промежуточного программного обеспечения. Ответы Razor Pages могут быть сжаты.
// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();
app.UseRouting();
app.UseResponseCompression();
app.MapRazorPages();
Дополнительные сведения об одностраничных приложениях см. в руководствах по шаблонам проектов React и Angular.
Порядок UseCors и UseStaticFiles
Порядок вызовов UseCors
и UseStaticFiles
зависит от приложения. Дополнительные сведения см. в разделе Порядок UseCors и UseStaticFiles.
Порядок промежуточного программного обеспечения для пересылаемых заголовков
Промежуточный слой для перенаправления заголовков должен выполняться перед другими промежуточными слоями. Такой порядок гарантирует, что промежуточное программное обеспечение, полагающееся на сведения о перенаправленных заголовках, может использовать значения заголовков для обработки. Чтобы запустить ПО перенаправления заголовков после ПО для диагностики и обработки ошибок, см. Порядок ПО перенаправления заголовков.
Разветвить конвейер промежуточного ПО
Расширения Map используются как условность для ветвления конвейера.
Map
разветвляет конвейер обработки запросов на основе совпадений с заданным путем запроса. Если путь запроса начинается с заданного пути, данная ветвь выполняется.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/map1", HandleMapTest1);
app.Map("/map2", HandleMapTest2);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleMapTest1(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
static void HandleMapTest2(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 2");
});
}
В таблице ниже приведены запросы и отклики http://localhost:1234
на базе предыдущего кода.
Запрос | Ответ |
---|---|
localhost:1234 | Привет от делегата, не относящегося к Map. |
localhost:1234/map1 | Тест карты 1 |
localhost:1234/map2 | Тест карты 2 |
localhost:1234/map3 | Привет от делегата, не относящегося к Map. |
Когда используется Map
, соответствующие сегменты путей удаляются из HttpRequest.Path
и добавляются к HttpRequest.PathBase
для каждого запроса.
Map
поддерживает вложение, например:
app.Map("/level1", level1App => {
level1App.Map("/level2a", level2AApp => {
// "/level1/level2a" processing
});
level1App.Map("/level2b", level2BApp => {
// "/level1/level2b" processing
});
});
Map
также может сопоставить несколько сегментов одновременно:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/map1/seg1", HandleMultiSeg);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleMultiSeg(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
MapWhen осуществляет ветвление конвейера запросов на основе результата заданного предиката. Любой предикат типа Func<HttpContext, bool>
можно использовать для сопоставления запросов с новой ветвью конвейера. В следующем примере предикат служит для определения наличия переменной строки запроса branch
.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleBranch(IApplicationBuilder app)
{
app.Run(async context =>
{
var branchVer = context.Request.Query["branch"];
await context.Response.WriteAsync($"Branch used = {branchVer}");
});
}
Ниже приведены запросы и отклики http://localhost:1234
на базе предыдущего кода.
Запрос | Ответ |
---|---|
localhost:1234 |
Hello from non-Map delegate. |
localhost:1234/?branch=main |
Branch used = main |
UseWhen также осуществляет ветвление конвейера запросов на основе результата заданного предиката. В отличие от MapWhen
, эта ветвь снова присоединяется к основному конвейеру, если она не делает короткое замыкание или не содержит терминальный промежуточный слой.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
appBuilder => HandleBranchAndRejoin(appBuilder));
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
void HandleBranchAndRejoin(IApplicationBuilder app)
{
var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>();
app.Use(async (context, next) =>
{
var branchVer = context.Request.Query["branch"];
logger.LogInformation("Branch used = {branchVer}", branchVer);
// Do work that doesn't write to the Response.
await next();
// Do other work that doesn't write to the Response.
});
}
В предыдущем примере ответ Hello from non-Map delegate.
записывается для всех запросов. Если запрос включает переменную строки запроса branch
, ее значение регистрируется до того, как будет выполнено повторное объединение с основным конвейером.
Встроенное посредническое ПО
ASP.NET Core содержит следующие компоненты промежуточного слоя. В столбце Порядок указаны сведения о размещении ПО промежуточного слоя в конвейере обработки запросов и условия, в соответствии с которыми ПО промежуточного слоя может прервать обработку запроса. Если промежуточный слой замыкает конвейер обработки запроса и препятствует обработке запроса дальнейшими компонентами промежуточного слоя, он называется терминальным промежуточным слоем. Дополнительные сведения о коротком замыкании см. в разделе «Создание конвейера ПО промежуточного слоя с WebApplication».
посредническое программное обеспечение | Описание | Заказ |
---|---|---|
Аутентификация | Обеспечивает поддержку проверки подлинности. | Перед тем, как потребуется HttpContext.User . Конечная точка для обратных вызовов OAuth. |
Авторизация | Обеспечивает поддержку авторизации. | Непосредственно после ПО промежуточного слоя для проверки подлинности. |
Политика Cookie | Обеспечивает отслеживание согласия пользователей на хранение личных сведений и соблюдение минимальных стандартов для полей cookie, таких как secure и SameSite . |
** Перед промежуточным ПО, которое выдает файлы cookie. Например: Authentication, Session, MVC (TempData). |
CORS | Настраивает общий доступ к ресурсам независимо от источника. | Ставится перед компонентами, использующими CORS.
UseCors сейчас нужно использовать перед UseResponseCaching из-за этой ошибки. |
DeveloperExceptionPage | Создает страницу со сведениями об ошибках, предназначенными для использования только в среде разработки. | Ставится перед компонентами, выдающими ошибки. Шаблоны проектов автоматически регистрируют это ПО промежуточного слоя в качестве первого в конвейере в среде разработки. |
Диагностика | Отдельное ПО промежуточного слоя, которое обеспечивает обработку исключений, предоставляет страницу исключений для разработчика, страницы состояния кода, веб-страницу по умолчанию для новых приложений. | Ставится перед компонентами, выдающими ошибки. Конечный пункт для обработки исключений или отображения веб-страницы по умолчанию для новых приложений. |
переадресованные заголовки | Пересылает заголовки прокси в текущий запрос. | Перед компонентами, использующими обновленные поля. Например: схема, узел, IP-адрес клиента, метод. |
Проверка работоспособности | Проверяет работоспособность приложения ASP.NET Core и его зависимостей, таких как проверка доступности базы данных. | Терминальным, если запрос соответствует терминальной точке проверки работоспособности. |
Распространение заголовков | Распространяет заголовки HTTP из входящего запроса на исходящие запросы HTTP-клиентов. | |
Ведение журнала HTTP | Регистрирует запросы и отклики HTTP. | В начале потока промежуточного программного обеспечения. |
Переопределение метода HTTP | Позволяет входящему запросу POST переопределить метод. | Ставится перед компонентами, использующими обновленный метод. |
Перенаправление HTTPS | Перенаправляет все запросы HTTP на HTTPS. | Ставится перед компонентами, использующими URL-адрес. |
Строгое обеспечение безопасности транспорта HTTP (HSTS) | ПО промежуточного слоя для повышения безопасности, которое добавляет специальный заголовок ответа. | Перед отправкой ответов и после компонентов, изменяющих запросы. Например: пересылка заголовков и переписывание URL. |
MVC; | Обрабатывает запросы с помощью MVC либо Razor Pages. | Является конечным, если запрос соответствует маршруту. |
OWIN | Взаимодействие с приложениями, серверами и промежуточным программным обеспечением на основе OWIN. | Конечный, если промежуточное программное обеспечение OWIN полностью обрабатывает запрос. |
Кэширование выходных данных | Предоставляет поддержку кэширования ответов на основе конфигурации. | Ставится перед компонентами, требующими кэширование.
UseRouting нужно использовать перед UseOutputCaching .
UseCORS нужно использовать перед UseOutputCaching . |
Кэширование ответов | Обеспечивает поддержку для кэширования откликов. Для этого требуется участие клиента в работе. Используйте кэширование выходных данных для полного управления сервером. | Ставится перед компонентами, требующими кэширование.
UseCORS нужно использовать перед UseResponseCaching . Обычно не подходит для приложений пользовательского интерфейса, таких как Pages, так как Razor браузеры обычно задают заголовки запросов, которые предотвращают кэширование.
Кэширование выходных данных обеспечивает преимущества приложений пользовательского интерфейса. |
Распаковка запросов | Обеспечивает поддержку распаковки запросов. | Ставится перед компонентами, которые считывают текст запроса. |
Сжатие откликов | Обеспечивает поддержку для сжатия откликов. | Ставится перед компонентами, требующими сжатие. |
Локализация запроса | Обеспечивает поддержку локализации. | Перед компонентами, чувствительными к локализации. Должно появляться после промежуточного ПО маршрутизации при использовании RouteDataRequestCultureProvider. |
Маршрутизация конечных точек | Определяет и ограничивает маршруты запросов. | Терминал для совпадающих маршрутов. |
Спа | Обрабатывает все запросы, начиная с этой точки в среде промежуточного слоя, возвращая страницу по умолчанию для одностраничного приложения (SPA) | В конце цепочки, чтобы другое ПО промежуточного слоя для обслуживания статических файлов, действий MVC и т. д. имело приоритет. |
Сеанс | Обеспечивает поддержку для управления пользовательскими сеансами. | Перед компонентами, которые требуют сеанса. |
Статические файлы | Обеспечивает поддержку для обработки статических файлов и просмотра каталогов. | Если запрос соответствует файлу, он является терминалом. |
Переопределение URL-адреса | Обеспечивает поддержку для переопределения URL-адресов и перенаправления запросов. | Ставится перед компонентами, использующими URL-адрес. |
W3CLogging | Создает журналы доступа к серверу в расширенном формате файла журнала W3C. | В начале потока промежуточного программного обеспечения. |
WebSockets | Обеспечивает поддержку протокола WebSockets. | Перед компонентами, которым нужно принимать запросы WebSocket. |
Дополнительные ресурсы
- Параметры времени существования и регистрации содержат полный пример посреднического ПО со службами, имеющими время существования scoped (с заданной областью), transient (временное) и singleton (одиночное).
- Написание пользовательского посредника ASP.NET Core
- Тестирование по промежуточному слоям ASP.NET Core
- Настройка gRPC-Web в ASP.NET Core
- Перенос модулей HTTP в ПО промежуточного слоя ASP.NET Core
- Запуск приложения в ASP.NET Core
- Функции запроса в ASP.NET Core
- Активация промежуточного ПО на основе фабрики в ASP.NET Core
- Активация ПО промежуточного слоя с помощью стороннего контейнера в ASP.NET Core
Авторы: Рик Андерсон (Rick Anderson) и Стив Смит (Steve Smith)
ПО промежуточного слоя — это программное обеспечение, выстраиваемое в виде конвейера приложения для обработки запросов и откликов. Каждый компонент:
- определяет, нужно ли передать запрос следующему компоненту в конвейере;
- может выполнять работу до и после следующего компонента в конвейере.
Для построения конвейера запросов используются делегаты запроса. Делегаты запросов обрабатывают каждый HTTP-запрос.
Делегаты запросов настраиваются с использованием методов расширения Run, Map и Use. Отдельный делегат запроса можно указать в виде встроенного анонимного метода (называемого посредником) либо определить в переиспользуемом классе. Эти многоразовые классы и встроенные анонимные методы являются промежуточным ПО или компонентами промежуточного слоя. Каждый компонент ПО промежуточного слоя в конвейере запросов отвечает за вызов следующего компонента в конвейере или замыкает конвейер. Когда промежуточный слой прерывает выполнение, он называется терминальным промежуточным слоем, так как препятствует обработке запроса другими промежуточными слоями.
Перенос модулей HTTP в ПО промежуточного слоя ASP.NET Core объясняет разницу между конвейерами запросов в ASP.NET Core и ASP.NET 4.x и предоставляет дополнительные примеры ПО промежуточного слоя.
Анализ кода ПО промежуточного слоя
ASP.NET Core содержит множество анализаторов .NET Compiler Platform, проверяющих качество кода приложения. Дополнительные сведения см. в статье Анализ кода в приложениях ASP.NET Core.
Создайте middleware-конвейер с помощью WebApplication
Конвейер запросов ASP.NET Core состоит из последовательности делегатов запроса, вызываемых один за другим. На следующей схеме демонстрируется этот принцип. Поток выполнения показан черными стрелками.
Каждый из делегатов может выполнять операции до и после следующего делегата. Делегаты обработки исключений должны вызываться в начале конвейера, чтобы перехватывать исключения, возникающие на более поздних этапах.
Простейшее приложение ASP.NET Core задает один делегат запроса, обрабатывающий все запросы. В этом случае конвейер запросов как таковой отсутствует. Вместо этого в ответ на каждый HTTP-запрос вызывается одна анонимная функция.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello world!");
});
app.Run();
Несколько делегатов запроса можно соединить в цепочку с помощью Use. Параметр next
представляет следующий делегат в конвейере. Вы можете прервать выполнение конвейера, не вызывая функцию next
. Обычно действия можно выполнять как до, так и после next
делегата, как показано в этом примере:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
// Do work that can write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
app.Run();
Если делегат не передает запрос следующему делегату, это называется замыканием конвейера запросов. Короткое замыкание часто является предпочтительным, так как позволяет избежать ненужной работы. Например, промежуточное ПО для статических файлов может выступать в качестве завершающего промежуточного ПО, обрабатывая запрос к статическому файлу и прерывая остальную часть конвейера. Компоненты промежуточного слоя, добавленные в конвейер перед промежуточным слоем, завершающим обработку, продолжают обработку кода после своих команд next.Invoke
. Примите во внимание следующее предупреждение о попытке записи в ответ, который уже был отправлен.
Предупреждение
Не вызывайте next.Invoke
после отправки отклика клиенту. Изменения HttpResponse после начала отправки ответа приведут к возникновению исключения. Например, при задании заголовков и кода состояния возникает исключение. Запись в тело отклика после вызова next
:
- может вызвать нарушение протокола, например, при записи более установленного значения
Content-Length
; - может привести к нарушению формата тела. например, при записи нижнего колонтитула HTML в CSS-файл.
HasStarted удобно использовать для обозначения того, были ли отправлены заголовки или выполнена запись в тело.
Делегаты Run не получают параметр next
. Первый делегат Run
всегда является конечным и завершает конвейер.
Run
— это соглашение. Некоторые компоненты промежуточного слоя могут предоставлять методы Run[Middleware]
, которые выполняются в конце конвейера:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (context, next) =>
{
// Do work that can write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
app.Run();
Если вы хотите увидеть комментарии к коду, переведенные на языки, отличные от английского, сообщите нам на странице обсуждения этой проблемы на сайте GitHub.
В предыдущем примере делегат Run
записывает "Hello from 2nd delegate."
в ответ и завершает конвейер. Если добавить другой делегат Use
или Run
после делегата Run
, он не будет вызван.
Рекомендуется использовать перегрузку app.Use, требующую передачи контекста в следующий компонент.
Метод расширения без выделения app.Use:
- Требует передачи контекста в
next
. - Сохраняет два внутренних выделения на один запрос, которые требуются при другой перегрузке.
Дополнительные сведения см. здесь на GitHub.
Порядок ПО промежуточного слоя
На следующей схеме показан полный конвейер обработки запросов для приложений ASP.NET Core MVC и Razor Pages. Вы можете увидеть, как в стандартном приложении упорядочены существующие программы промежуточного слоя и где добавляются пользовательские программы промежуточного слоя. Вы можете полностью контролировать изменение порядка существующего ПО промежуточного слоя или внедрять новое пользовательское ПО промежуточного слоя для своих сценариев.
Промежуточное ПО конечной точки на предыдущей схеме выполняет конвейер фильтра для соответствующего типа приложения — MVC или страниц.
Промежуточное ПО Маршрутизации на вышеуказанной схеме размещено после Статических файлов. В таком порядке реализуются шаблоны проектов путем явного вызова app.UseRouting. Если вы не вызываете app.UseRouting
, то промежуточное ПО маршрутизации по умолчанию запускается в начале конвейера. Дополнительные сведения см. в разделе Маршрутизация.
Порядок добавления компонентов ПО промежуточного слоя в Program.cs
файл определяет порядок вызова компонентов ПО промежуточного слоя для запросов и обратного порядка ответа. Соблюдать этот порядок крайне важно для обеспечения безопасности, производительности и функциональности.
Следующий выделенный код в Program.cs
добавляет компоненты промежуточного слоя, связанные с безопасностью, в типично рекомендуемом порядке.
using IndividualAccountsExample.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();
app.UseRouting();
// app.UseRequestLocalization();
// app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();
app.MapRazorPages();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
В предыдущем коде:
- ПО промежуточного слоя, которое не было добавлено при создании веб-приложения с учетными записями отдельных пользователей, деактивируется.
- Не каждое промежуточное программное обеспечение появляется в этом точном порядке, но многие из них соблюдают его. Например:
-
UseCors
,UseAuthentication
иUseAuthorization
должны присутствовать в указанном порядке. - Сейчас
UseCors
нужно использовать передUseResponseCaching
. Это требование объясняется в вопросе GitHub по адресу dotnet/aspnetcore #23218. -
UseRequestLocalization
нужно использовать перед любым ПО промежуточного слоя, которое может проверять язык и региональные параметры запроса (например,app.UseMvcWithDefaultRoute()
).
-
В некоторых сценариях ПО промежуточного слоя имеет другой порядок. Например, порядок кэширования и сжатия зависит от сценария, и существует несколько допустимых вариантов такого порядка. Например:
app.UseResponseCaching();
app.UseResponseCompression();
С помощью приведенного выше кода можно снизить загрузку ЦП путем кэширования сжатого ответа, но при этом может быть выполнено кэширование нескольких представлений ресурса с помощью разных алгоритмов сжатия, таких как Gzip или Brotli.
В приведенном ниже порядке объединяются статические файлы, чтобы разрешить кэширование сжатых статических файлов.
app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();
Program.cs
Следующий код добавляет компоненты ПО промежуточного слоя для распространенных сценариев приложений:
- Обработка исключений и ошибок
- При запуске приложения в среде разработки:
- Промежуточное ПО для страницы исключений разработчика (UseDeveloperExceptionPage) сообщает об ошибках выполнения приложения.
- Промежуточное программное обеспечение страницы ошибок базы данных (UseDatabaseErrorPage) сообщает об ошибках времени выполнения базы данных.
- При запуске приложения в рабочей среде:
- Промежуточное ПО обработчика исключений (UseExceptionHandler) перехватывает исключения, возникшие в следующих промежуточных слоях.
- Промежуточный слой (middleware) протокола HSTS (HTTP Strict Transport Security) (UseHsts) добавляет заголовок
Strict-Transport-Security
.
- При запуске приложения в среде разработки:
- Промежуточное ПО для перенаправления HTTPS (UseHttpsRedirection) перенаправляет запросы с HTTP на HTTPS.
- Промежуточное ПО для статических файлов (UseStaticFiles) возвращает статические файлы и прерывает дальнейшую обработку запросов.
- Программное обеспечение Middleware Cookie (UseCookiePolicy) обеспечивает соответствие приложения требованиям Общего регламента по защите данных (GDPR) ЕС.
- Промежуточное ПО маршрутизации (UseRouting) для маршрутизации запросов.
- ПО промежуточного слоя проверки подлинности (UseAuthentication) пытается проверить подлинность пользователя, прежде чем предоставить ему доступ к защищенным ресурсам.
- ПО промежуточного слоя авторизации (UseAuthorization) разрешает пользователю доступ к защищенным ресурсам.
- Промежуточное ПО сеанса (UseSession) устанавливает и поддерживает состояние сеанса. Если в приложении используется состояние сеанса, вызовите промежуточное ПО сеанса после промежуточного ПО политики Cookie и до промежуточного ПО MVC.
- Промежуточное ПО маршрутизации конечных точек (UseEndpoints с MapRazorPages) для добавления конечных точек страниц Razor в конвейер запросов.
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();
В предыдущем примере кода каждый метод расширения промежуточного слоя предоставляется в WebApplicationBuilder с использованием пространства имен Microsoft.AspNetCore.Builder.
UseExceptionHandler — это первый компонент промежуточного слоя, добавленный в конвейер. Таким образом, промежуточное ПО для обработки исключений перехватывает все исключения, возникающие в последующих вызовах.
Промежуточный компонент статических файлов вызывается на ранних этапах конвейера. Это позволяет ему обрабатывать запросы и прекратить обработку, минуя остальные компоненты. Этот компонент статических файлов не выполняет проверки авторизации. Все файлы, обслуживаемые промежуточным программным обеспечением для статических файлов, включая те, что находятся в wwwroot, находятся в открытом доступе. Сведения о защите статических файлов см. в статье Статические файлы в ASP.NET Core.
Если запрос не обрабатывается компонентом промежуточного слоя для статических файлов, он передается в компонент промежуточного слоя для проверки подлинности (UseAuthentication), который выполняет проверку подлинности. Аутентификация не прерывает необработанные запросы. Хотя промежуточное программное обеспечение для аутентификации проверяет подлинность запросов, авторизация (и отклонение) выполняются только после того, как MVC выберет указанную страницу или контроллер MVC и action.
Следующий пример демонстрирует порядок работы компонентов промежуточного ПО, в котором запросы на статические файлы обрабатываются компонентом для статических файлов до компонента для сжатия ответов. Статические файлы не сжимаются при таком порядке промежуточного программного обеспечения. Ответы Razor Pages могут быть сжаты.
// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();
app.UseRouting();
app.UseResponseCompression();
app.MapRazorPages();
Дополнительные сведения об одностраничных приложениях см. в руководствах по шаблонам проектов React и Angular.
Порядок UseCors и UseStaticFiles
Порядок вызовов UseCors
и UseStaticFiles
зависит от приложения. Дополнительные сведения см. в разделе Порядок UseCors и UseStaticFiles.
Порядок промежуточного программного обеспечения для пересылаемых заголовков
Промежуточный слой для перенаправления заголовков должен выполняться перед другими промежуточными слоями. Такой порядок гарантирует, что промежуточное программное обеспечение, полагающееся на сведения о перенаправленных заголовках, может использовать значения заголовков для обработки. Чтобы запустить ПО перенаправления заголовков после ПО для диагностики и обработки ошибок, см. Порядок ПО перенаправления заголовков.
Разветвить конвейер промежуточного ПО
Расширения Map используются как условность для ветвления конвейера.
Map
разветвляет конвейер обработки запросов на основе совпадений с заданным путем запроса. Если путь запроса начинается с заданного пути, данная ветвь выполняется.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/map1", HandleMapTest1);
app.Map("/map2", HandleMapTest2);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleMapTest1(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
static void HandleMapTest2(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 2");
});
}
В таблице ниже приведены запросы и отклики http://localhost:1234
на базе предыдущего кода.
Запрос | Ответ |
---|---|
localhost:1234 | Привет от делегата, не относящегося к Map. |
localhost:1234/map1 | Тест карты 1 |
localhost:1234/map2 | Тест карты 2 |
localhost:1234/map3 | Привет от делегата, не относящегося к Map. |
Когда используется Map
, соответствующие сегменты путей удаляются из HttpRequest.Path
и добавляются к HttpRequest.PathBase
для каждого запроса.
Map
поддерживает вложение, например:
app.Map("/level1", level1App => {
level1App.Map("/level2a", level2AApp => {
// "/level1/level2a" processing
});
level1App.Map("/level2b", level2BApp => {
// "/level1/level2b" processing
});
});
Map
также может сопоставить несколько сегментов одновременно:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/map1/seg1", HandleMultiSeg);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleMultiSeg(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
MapWhen осуществляет ветвление конвейера запросов на основе результата заданного предиката. Любой предикат типа Func<HttpContext, bool>
можно использовать для сопоставления запросов с новой ветвью конвейера. В следующем примере предикат служит для определения наличия переменной строки запроса branch
.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
static void HandleBranch(IApplicationBuilder app)
{
app.Run(async context =>
{
var branchVer = context.Request.Query["branch"];
await context.Response.WriteAsync($"Branch used = {branchVer}");
});
}
Ниже приведены запросы и отклики http://localhost:1234
на базе предыдущего кода.
Запрос | Ответ |
---|---|
localhost:1234 |
Hello from non-Map delegate. |
localhost:1234/?branch=main |
Branch used = main |
UseWhen также осуществляет ветвление конвейера запросов на основе результата заданного предиката. В отличие от MapWhen
, эта ветвь снова присоединяется к основному конвейеру, если она не делает короткое замыкание или не содержит терминальный промежуточный слой.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
appBuilder => HandleBranchAndRejoin(appBuilder));
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
app.Run();
void HandleBranchAndRejoin(IApplicationBuilder app)
{
var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>();
app.Use(async (context, next) =>
{
var branchVer = context.Request.Query["branch"];
logger.LogInformation("Branch used = {branchVer}", branchVer);
// Do work that doesn't write to the Response.
await next();
// Do other work that doesn't write to the Response.
});
}
В предыдущем примере ответ Hello from non-Map delegate.
записывается для всех запросов. Если запрос включает переменную строки запроса branch
, ее значение регистрируется до того, как будет выполнено повторное объединение с основным конвейером.
Встроенное посредническое ПО
ASP.NET Core содержит следующие компоненты промежуточного слоя. В столбце Порядок указаны сведения о размещении ПО промежуточного слоя в конвейере обработки запросов и условия, в соответствии с которыми ПО промежуточного слоя может прервать обработку запроса. Если промежуточный слой замыкает конвейер обработки запроса и препятствует обработке запроса дальнейшими компонентами промежуточного слоя, он называется терминальным промежуточным слоем. Дополнительные сведения о коротком замыкании см. в разделе «Создание конвейера ПО промежуточного слоя с WebApplication».
посредническое программное обеспечение | Описание | Заказ |
---|---|---|
Аутентификация | Обеспечивает поддержку проверки подлинности. | Перед тем, как потребуется HttpContext.User . Конечная точка для обратных вызовов OAuth. |
Авторизация | Обеспечивает поддержку авторизации. | Непосредственно после ПО промежуточного слоя для проверки подлинности. |
Политика Cookie | Обеспечивает отслеживание согласия пользователей на хранение личных сведений и соблюдение минимальных стандартов для полей cookie, таких как secure и SameSite . |
** Перед промежуточным ПО, которое выдает файлы cookie. Например: Authentication, Session, MVC (TempData). |
CORS | Настраивает общий доступ к ресурсам независимо от источника. | Ставится перед компонентами, использующими CORS.
UseCors сейчас нужно использовать перед UseResponseCaching из-за этой ошибки. |
DeveloperExceptionPage | Создает страницу со сведениями об ошибках, предназначенными для использования только в среде разработки. | Ставится перед компонентами, выдающими ошибки. Шаблоны проектов автоматически регистрируют это ПО промежуточного слоя в качестве первого в конвейере в среде разработки. |
Диагностика | Отдельное ПО промежуточного слоя, которое обеспечивает обработку исключений, предоставляет страницу исключений для разработчика, страницы состояния кода, веб-страницу по умолчанию для новых приложений. | Ставится перед компонентами, выдающими ошибки. Конечный пункт для обработки исключений или отображения веб-страницы по умолчанию для новых приложений. |
переадресованные заголовки | Пересылает заголовки прокси в текущий запрос. | Перед компонентами, использующими обновленные поля. Например: схема, узел, IP-адрес клиента, метод. |
Проверка работоспособности | Проверяет работоспособность приложения ASP.NET Core и его зависимостей, таких как проверка доступности базы данных. | Терминальным, если запрос соответствует терминальной точке проверки работоспособности. |
Распространение заголовков | Распространяет заголовки HTTP из входящего запроса на исходящие запросы HTTP-клиентов. | |
Ведение журнала HTTP | Регистрирует запросы и отклики HTTP. | В начале потока промежуточного программного обеспечения. |
Переопределение метода HTTP | Позволяет входящему запросу POST переопределить метод. | Ставится перед компонентами, использующими обновленный метод. |
Перенаправление HTTPS | Перенаправляет все запросы HTTP на HTTPS. | Ставится перед компонентами, использующими URL-адрес. |
Строгое обеспечение безопасности транспорта HTTP (HSTS) | ПО промежуточного слоя для повышения безопасности, которое добавляет специальный заголовок ответа. | Перед отправкой ответов и после компонентов, изменяющих запросы. Например: пересылка заголовков и переписывание URL. |
MVC; | Обрабатывает запросы с помощью MVC либо Razor Pages. | Является конечным, если запрос соответствует маршруту. |
OWIN | Взаимодействие с приложениями, серверами и промежуточным программным обеспечением на основе OWIN. | Конечный, если промежуточное программное обеспечение OWIN полностью обрабатывает запрос. |
Распаковка запросов | Обеспечивает поддержку распаковки запросов. | Ставится перед компонентами, которые считывают текст запроса. |
Кэширование ответов | Обеспечивает поддержку для кэширования откликов. | Ставится перед компонентами, требующими кэширование.
UseCORS нужно использовать перед UseResponseCaching . |
Сжатие откликов | Обеспечивает поддержку для сжатия откликов. | Ставится перед компонентами, требующими сжатие. |
Локализация запроса | Обеспечивает поддержку локализации. | Перед компонентами, чувствительными к локализации. Должно появляться после промежуточного ПО маршрутизации при использовании RouteDataRequestCultureProvider. |
Маршрутизация конечных точек | Определяет и ограничивает маршруты запросов. | Терминал для совпадающих маршрутов. |
Спа | Обрабатывает все запросы, начиная с этой точки в среде промежуточного слоя, возвращая страницу по умолчанию для одностраничного приложения (SPA) | В конце цепочки, чтобы другое ПО промежуточного слоя для обслуживания статических файлов, действий MVC и т. д. имело приоритет. |
Сеанс | Обеспечивает поддержку для управления пользовательскими сеансами. | Перед компонентами, которые требуют сеанса. |
Статические файлы | Обеспечивает поддержку для обработки статических файлов и просмотра каталогов. | Если запрос соответствует файлу, он является терминалом. |
Переопределение URL-адреса | Обеспечивает поддержку для переопределения URL-адресов и перенаправления запросов. | Ставится перед компонентами, использующими URL-адрес. |
W3CLogging | Создает журналы доступа к серверу в расширенном формате файла журнала W3C. | В начале потока промежуточного программного обеспечения. |
WebSockets | Обеспечивает поддержку протокола WebSockets. | Перед компонентами, которым нужно принимать запросы WebSocket. |
Дополнительные ресурсы
- Параметры времени существования и регистрации содержат полный пример посреднического ПО со службами, имеющими время существования scoped (с заданной областью), transient (временное) и singleton (одиночное).
- Написание пользовательского посредника ASP.NET Core
- Тестирование по промежуточному слоям ASP.NET Core
- Настройка gRPC-Web в ASP.NET Core
- Перенос модулей HTTP в ПО промежуточного слоя ASP.NET Core
- Запуск приложения в ASP.NET Core
- Функции запроса в ASP.NET Core
- Активация промежуточного ПО на основе фабрики в ASP.NET Core
- Активация ПО промежуточного слоя с помощью стороннего контейнера в ASP.NET Core
Авторы: Рик Андерсон (Rick Anderson) и Стив Смит (Steve Smith)
ПО промежуточного слоя — это программное обеспечение, выстраиваемое в виде конвейера приложения для обработки запросов и откликов. Каждый компонент:
- определяет, нужно ли передать запрос следующему компоненту в конвейере;
- может выполнять работу до и после следующего компонента в конвейере.
Для построения конвейера запросов используются делегаты запроса. Делегаты запросов обрабатывают каждый HTTP-запрос.
Делегаты запросов настраиваются с использованием методов расширения Run, Map и Use. Отдельный делегат запроса можно указать в виде встроенного анонимного метода (называемого посредником) либо определить в переиспользуемом классе. Эти многоразовые классы и встроенные анонимные методы являются промежуточным ПО или компонентами промежуточного слоя. Каждый компонент ПО промежуточного слоя в конвейере запросов отвечает за вызов следующего компонента в конвейере или замыкает конвейер. Когда промежуточный слой прерывает выполнение, он называется терминальным промежуточным слоем, так как препятствует обработке запроса другими промежуточными слоями.
Перенос модулей HTTP в ПО промежуточного слоя ASP.NET Core объясняет разницу между конвейерами запросов в ASP.NET Core и ASP.NET 4.x и предоставляет дополнительные примеры ПО промежуточного слоя.
Создание конвейера ПО промежуточного слоя с помощью IApplicationBuilder
Конвейер запросов ASP.NET Core состоит из последовательности делегатов запроса, вызываемых один за другим. На следующей схеме демонстрируется этот принцип. Поток выполнения показан черными стрелками.
Каждый из делегатов может выполнять операции до и после следующего делегата. Делегаты обработки исключений должны вызываться в начале конвейера, чтобы перехватывать исключения, возникающие на более поздних этапах.
Простейшее приложение ASP.NET Core задает один делегат запроса, обрабатывающий все запросы. В этом случае конвейер запросов как таковой отсутствует. Вместо этого в ответ на каждый HTTP-запрос вызывается одна анонимная функция.
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Hello, World!");
});
}
}
Несколько делегатов запроса можно соединить в цепочку с помощью Use. Параметр next
представляет следующий делегат в конвейере. Вы можете прервать поток, не вызывая параметр next. Обычно действия можно выполнять как до, так и после следующего делегата, как показано в этом примере.
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
// Do work that doesn't write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
}
}
Если делегат не передает запрос следующему делегату, это называется замыканием конвейера запросов. Короткое замыкание часто является предпочтительным, так как позволяет избежать ненужной работы. Например, промежуточное ПО для статических файлов может выступать в качестве завершающего промежуточного ПО, обрабатывая запрос к статическому файлу и прерывая остальную часть конвейера. Компоненты промежуточного слоя, добавленные в конвейер перед промежуточным слоем, завершающим обработку, продолжают обработку кода после своих команд next.Invoke
. Примите во внимание следующее предупреждение о попытке записи в ответ, который уже был отправлен.
Предупреждение
Не вызывайте next.Invoke
после отправки отклика клиенту. Изменения HttpResponse после начала отправки ответа приведут к возникновению исключения. Например, при задании заголовков и кода состояния возникает исключение. Запись в тело отклика после вызова next
:
- может вызвать нарушение протокола, например, при записи более установленного значения
Content-Length
; - может привести к нарушению формата тела. например, при записи нижнего колонтитула HTML в CSS-файл.
HasStarted удобно использовать для обозначения того, были ли отправлены заголовки или выполнена запись в тело.
Делегаты Run не получают параметр next
. Первый делегат Run
всегда является конечным и завершает конвейер.
Run
— это соглашение. Некоторые компоненты промежуточного слоя могут предоставлять методы Run[Middleware]
, которые выполняются в конце конвейера:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
// Do work that doesn't write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
}
}
Если вы хотите увидеть комментарии к коду, переведенные на языки, отличные от английского, сообщите нам на странице обсуждения этой проблемы на сайте GitHub.
В предыдущем примере делегат Run
записывает "Hello from 2nd delegate."
в ответ и завершает конвейер. Если добавить другой делегат Use
или Run
после делегата Run
, он не будет вызван.
Порядок ПО промежуточного слоя
На следующей схеме показан полный конвейер обработки запросов для приложений ASP.NET Core MVC и Razor Pages. Вы можете увидеть, как в стандартном приложении упорядочены существующие программы промежуточного слоя и где добавляются пользовательские программы промежуточного слоя. Вы можете полностью контролировать изменение порядка существующего ПО промежуточного слоя или внедрять новое пользовательское ПО промежуточного слоя для своих сценариев.
Промежуточное ПО конечной точки на предыдущей схеме выполняет конвейер фильтра для соответствующего типа приложения — MVC или страниц.
Порядок, в котором компоненты промежуточного слоя добавляются в метод Startup.Configure
, определяет порядок их вызова при запросах и обратный порядок для отклика. Соблюдать этот порядок крайне важно для обеспечения безопасности, производительности и функциональности.
Следующий метод Startup.Configure
добавляет связанные с безопасностью компоненты ПО промежуточного слоя в стандартном рекомендуемом порядке:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();
app.UseRouting();
// app.UseRequestLocalization();
// app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
В предыдущем коде:
- ПО промежуточного слоя, которое не было добавлено при создании веб-приложения с учетными записями отдельных пользователей, деактивируется.
- Не каждое промежуточное программное обеспечение появляется в этом точном порядке, но многие из них соблюдают его. Например:
-
UseCors
,UseAuthentication
иUseAuthorization
должны присутствовать в указанном порядке. - Сейчас
UseCors
нужно использовать передUseResponseCaching
из-за этой ошибки. -
UseRequestLocalization
нужно использовать перед любым ПО промежуточного слоя, которое может проверять язык и региональные параметры запроса (например,app.UseMvcWithDefaultRoute()
).
-
В некоторых сценариях ПО промежуточного слоя имеет другой порядок. Например, порядок кэширования и сжатия зависит от сценария, и существует несколько допустимых вариантов такого порядка. Например:
app.UseResponseCaching();
app.UseResponseCompression();
С помощью приведенного выше кода можно экономить ресурсы ЦП путем кэширования сжатого ответа, но при этом может быть выполнено кэширование нескольких представлений ресурса с помощью разных алгоритмов сжатия, таких как Gzip или Brotli.
В приведенном ниже порядке объединяются статические файлы, чтобы разрешить кэширование сжатых статических файлов.
app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();
Метод Startup.Configure
добавляет компоненты ПО промежуточного слоя для распространенных сценариев приложений:
- Обработка исключений и ошибок
- При запуске приложения в среде разработки:
- Промежуточное ПО для страницы исключений разработчика (UseDeveloperExceptionPage) сообщает об ошибках выполнения приложения.
- ПО промежуточного слоя страниц ошибок базы данных отчитывает об ошибках среды выполнения базы данных.
- При запуске приложения в рабочей среде:
- Промежуточное ПО обработчика исключений (UseExceptionHandler) перехватывает исключения, возникшие в следующих промежуточных слоях.
- Промежуточный слой (middleware) протокола HSTS (HTTP Strict Transport Security) (UseHsts) добавляет заголовок
Strict-Transport-Security
.
- При запуске приложения в среде разработки:
- Промежуточное ПО для перенаправления HTTPS (UseHttpsRedirection) перенаправляет запросы с HTTP на HTTPS.
- Промежуточное ПО для статических файлов (UseStaticFiles) возвращает статические файлы и прерывает дальнейшую обработку запросов.
- Программное обеспечение Middleware Cookie (UseCookiePolicy) обеспечивает соответствие приложения требованиям Общего регламента по защите данных (GDPR) ЕС.
- Промежуточное ПО маршрутизации (UseRouting) для маршрутизации запросов.
- ПО промежуточного слоя проверки подлинности (UseAuthentication) пытается проверить подлинность пользователя, прежде чем предоставить ему доступ к защищенным ресурсам.
- ПО промежуточного слоя авторизации (UseAuthorization) разрешает пользователю доступ к защищенным ресурсам.
- Промежуточное ПО сеанса (UseSession) устанавливает и поддерживает состояние сеанса. Если в приложении используется состояние сеанса, вызовите промежуточное ПО сеанса после промежуточного ПО политики Cookie и до промежуточного ПО MVC.
- Промежуточное ПО маршрутизации конечных точек (UseEndpoints с MapRazorPages) для добавления конечных точек страниц Razor в конвейер запросов.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
В предыдущем примере кода каждый метод расширения промежуточного слоя предоставляется в IApplicationBuilder с использованием пространства имен Microsoft.AspNetCore.Builder.
UseExceptionHandler — это первый компонент промежуточного слоя, добавленный в конвейер. Таким образом, промежуточное ПО для обработки исключений перехватывает все исключения, возникающие в последующих вызовах.
Промежуточный компонент статических файлов вызывается на ранних этапах конвейера. Это позволяет ему обрабатывать запросы и прекратить обработку, минуя остальные компоненты. Этот компонент статических файлов не выполняет проверки авторизации. Все файлы, обслуживаемые промежуточным программным обеспечением для статических файлов, включая те, что находятся в wwwroot, находятся в открытом доступе. Сведения о защите статических файлов см. в статье Статические файлы в ASP.NET Core.
Если запрос не обрабатывается компонентом промежуточного слоя для статических файлов, он передается в компонент промежуточного слоя для проверки подлинности (UseAuthentication), который выполняет проверку подлинности. Аутентификация не прерывает необработанные запросы. Хотя промежуточное программное обеспечение для аутентификации проверяет подлинность запросов, авторизация (и отклонение) выполняются только после того, как MVC выберет указанную страницу или контроллер MVC и action.
Следующий пример демонстрирует порядок работы компонентов промежуточного ПО, в котором запросы на статические файлы обрабатываются компонентом для статических файлов до компонента для сжатия ответов. Статические файлы не сжимаются при таком порядке промежуточного программного обеспечения. Ответы Razor Pages могут быть сжаты.
public void Configure(IApplicationBuilder app)
{
// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();
app.UseRouting();
app.UseResponseCompression();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Для одностраничных приложений (SPA) ПО промежуточного слоя SPA UseSpaStaticFiles обычно поступает в конвейер ПО промежуточного слоя последним. ПО промежуточного слоя SPA поступает последним:
- Чтобы разрешить остальным ПО промежуточного слоя отвечать на запросы сопоставления в первую очередь.
- Чтобы разрешить выполнение одностраничных приложений с маршрутизацией на стороне клиента для всех маршрутов, которые не распознаются серверным приложением.
Дополнительные сведения об SPA см. в руководствах по шаблонам проектов React и Angular.
Порядок промежуточного программного обеспечения для пересылаемых заголовков
Промежуточный слой для перенаправления заголовков должен выполняться перед другими промежуточными слоями. Такой порядок гарантирует, что промежуточное программное обеспечение, полагающееся на сведения о перенаправленных заголовках, может использовать значения заголовков для обработки. Чтобы запустить ПО перенаправления заголовков после ПО для диагностики и обработки ошибок, см. Порядок ПО перенаправления заголовков.
Разветвить конвейер промежуточного ПО
Расширения Map используются как условность для ветвления конвейера.
Map
разветвляет конвейер обработки запросов на основе совпадений с заданным путем запроса. Если путь запроса начинается с заданного пути, данная ветвь выполняется.
public class Startup
{
private static void HandleMapTest1(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 1");
});
}
private static void HandleMapTest2(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test 2");
});
}
public void Configure(IApplicationBuilder app)
{
app.Map("/map1", HandleMapTest1);
app.Map("/map2", HandleMapTest2);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
}
}
Ниже приведены запросы и отклики http://localhost:1234
на базе предыдущего кода.
Запрос | Ответ |
---|---|
localhost:1234 | Привет от делегата, не относящегося к Map. |
localhost:1234/map1 | Тест карты 1 |
localhost:1234/map2 | Тест карты 2 |
localhost:1234/map3 | Привет от делегата, не относящегося к Map. |
Когда используется Map
, соответствующие сегменты путей удаляются из HttpRequest.Path
и добавляются к HttpRequest.PathBase
для каждого запроса.
Map
поддерживает вложение, например:
app.Map("/level1", level1App => {
level1App.Map("/level2a", level2AApp => {
// "/level1/level2a" processing
});
level1App.Map("/level2b", level2BApp => {
// "/level1/level2b" processing
});
});
Map
также может сопоставить несколько сегментов одновременно:
public class Startup
{
private static void HandleMultiSeg(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Map multiple segments.");
});
}
public void Configure(IApplicationBuilder app)
{
app.Map("/map1/seg1", HandleMultiSeg);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
}
}
MapWhen осуществляет ветвление конвейера запросов на основе результата заданного предиката. Любой предикат типа Func<HttpContext, bool>
можно использовать для сопоставления запросов с новой ветвью конвейера. В следующем примере предикат служит для определения наличия переменной строки запроса branch
.
public class Startup
{
private static void HandleBranch(IApplicationBuilder app)
{
app.Run(async context =>
{
var branchVer = context.Request.Query["branch"];
await context.Response.WriteAsync($"Branch used = {branchVer}");
});
}
public void Configure(IApplicationBuilder app)
{
app.MapWhen(context => context.Request.Query.ContainsKey("branch"),
HandleBranch);
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate.");
});
}
}
Ниже приведены запросы и отклики http://localhost:1234
на базе предыдущего кода.
Запрос | Ответ |
---|---|
localhost:1234 | Привет от делегата, не относящегося к Map. |
localhost:1234/?branch=main | Ветка используется = main |
UseWhen также осуществляет ветвление конвейера запросов на основе результата заданного предиката. В отличие от MapWhen
, эта ветвь снова присоединяется к основному конвейеру, если она не делает короткое замыкание или не содержит терминальный промежуточный слой.
public class Startup
{
private void HandleBranchAndRejoin(IApplicationBuilder app, ILogger<Startup> logger)
{
app.Use(async (context, next) =>
{
var branchVer = context.Request.Query["branch"];
logger.LogInformation("Branch used = {branchVer}", branchVer);
// Do work that doesn't write to the Response.
await next();
// Do other work that doesn't write to the Response.
});
}
public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
appBuilder => HandleBranchAndRejoin(appBuilder, logger));
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from main pipeline.");
});
}
}
В предыдущем примере для всех запросов записывается ответ "Привет от главного канала.". Если запрос включает переменную строки запроса branch
, ее значение регистрируется до того, как будет выполнено повторное объединение с основным конвейером.
Встроенное посредническое ПО
ASP.NET Core содержит следующие компоненты промежуточного слоя. В столбце Порядок указаны сведения о размещении ПО промежуточного слоя в конвейере обработки запросов и условия, в соответствии с которыми ПО промежуточного слоя может прервать обработку запроса. Если промежуточный слой замыкает конвейер обработки запроса и препятствует обработке запроса дальнейшими компонентами промежуточного слоя, он называется терминальным промежуточным слоем. Дополнительные сведения о коротком замыкании см. в разделе Создание конвейера ПО промежуточного слоя с помощью IApplicationBuilder.
посредническое программное обеспечение | Описание | Заказ |
---|---|---|
Защита от подделок | Предоставляет поддержку защиты от подделки запросов. | После проверки подлинности и авторизации, перед переходом к конечным точкам. |
Аутентификация | Обеспечивает поддержку проверки подлинности. | Перед тем, как потребуется HttpContext.User . Конечная точка для обратных вызовов OAuth. |
Авторизация | Обеспечивает поддержку авторизации. | Непосредственно после ПО промежуточного слоя для проверки подлинности. |
Политика Cookie | Обеспечивает отслеживание согласия пользователей на хранение личных сведений и соблюдение минимальных стандартов для полей cookie, таких как secure и SameSite . |
** Перед промежуточным ПО, которое выдает файлы cookie. Например: Authentication, Session, MVC (TempData). |
CORS | Настраивает общий доступ к ресурсам независимо от источника. | Ставится перед компонентами, использующими CORS.
UseCors сейчас нужно использовать перед UseResponseCaching из-за этой ошибки. |
Диагностика | Отдельное ПО промежуточного слоя, которое обеспечивает обработку исключений, предоставляет страницу исключений для разработчика, страницы состояния кода, веб-страницу по умолчанию для новых приложений. | Ставится перед компонентами, выдающими ошибки. Конечный пункт для обработки исключений или отображения веб-страницы по умолчанию для новых приложений. |
переадресованные заголовки | Пересылает заголовки прокси в текущий запрос. | Перед компонентами, использующими обновленные поля. Например: схема, узел, IP-адрес клиента, метод. |
Проверка работоспособности | Проверяет работоспособность приложения ASP.NET Core и его зависимостей, таких как проверка доступности базы данных. | Терминальным, если запрос соответствует терминальной точке проверки работоспособности. |
Распространение заголовков | Распространяет заголовки HTTP из входящего запроса на исходящие запросы HTTP-клиентов. | |
Переопределение метода HTTP | Позволяет входящему запросу POST переопределить метод. | Ставится перед компонентами, использующими обновленный метод. |
Перенаправление HTTPS | Перенаправляет все запросы HTTP на HTTPS. | Ставится перед компонентами, использующими URL-адрес. |
Строгое обеспечение безопасности транспорта HTTP (HSTS) | ПО промежуточного слоя для повышения безопасности, которое добавляет специальный заголовок ответа. | Перед отправкой ответов и после компонентов, изменяющих запросы. Например: пересылка заголовков и переписывание URL. |
MVC; | Обрабатывает запросы с помощью MVC либо Razor Pages. | Является конечным, если запрос соответствует маршруту. |
OWIN | Взаимодействие с приложениями, серверами и промежуточным программным обеспечением на основе OWIN. | Конечный, если промежуточное программное обеспечение OWIN полностью обрабатывает запрос. |
Кэширование ответов | Обеспечивает поддержку для кэширования откликов. | Ставится перед компонентами, требующими кэширование.
UseCORS нужно использовать перед UseResponseCaching . |
Сжатие откликов | Обеспечивает поддержку для сжатия откликов. | Ставится перед компонентами, требующими сжатие. |
Локализация запроса | Обеспечивает поддержку локализации. | Перед компонентами, чувствительными к локализации. Должно появляться после промежуточного ПО маршрутизации при использовании RouteDataRequestCultureProvider. |
Маршрутизация конечных точек | Определяет и ограничивает маршруты запросов. | Терминал для совпадающих маршрутов. |
Спа | Обрабатывает все запросы, начиная с этой точки в среде промежуточного слоя, возвращая страницу по умолчанию для одностраничного приложения (SPA) | В конце цепочки, чтобы другое ПО промежуточного слоя для обслуживания статических файлов, действий MVC и т. д. имело приоритет. |
Сеанс | Обеспечивает поддержку для управления пользовательскими сеансами. | Перед компонентами, которые требуют сеанса. |
Статические файлы | Обеспечивает поддержку для обработки статических файлов и просмотра каталогов. | Если запрос соответствует файлу, он является терминалом. |
Переопределение URL-адреса | Обеспечивает поддержку для переопределения URL-адресов и перенаправления запросов. | Ставится перед компонентами, использующими URL-адрес. |
WebSockets | Обеспечивает поддержку протокола WebSocket. | Перед компонентами, которым нужно принимать запросы WebSocket. |
Дополнительные ресурсы
- Параметры времени существования и регистрации содержат полный пример посреднического ПО со службами, имеющими время существования scoped (с заданной областью), transient (временное) и singleton (одиночное).
- Написание пользовательского посредника ASP.NET Core
- Тестирование по промежуточному слоям ASP.NET Core
- Перенос модулей HTTP в ПО промежуточного слоя ASP.NET Core
- Запуск приложения в ASP.NET Core
- Функции запроса в ASP.NET Core
- Активация промежуточного ПО на основе фабрики в ASP.NET Core
- Активация ПО промежуточного слоя с помощью стороннего контейнера в ASP.NET Core
ASP.NET Core