Поделиться через


Промежуточное ПО ASP.NET Core

Примечание.

Это не последняя версия этой статьи. В текущей версии см. версию .NET 10 этой статьи.

Предупреждение

Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущей версии см. версию .NET 10 этой статьи.

ПО промежуточного слоя — это программное обеспечение, выстраиваемое в виде конвейера приложения для обработки запросов и откликов. Каждое ПО промежуточного слоя:

  • Определяет, следует ли передавать запрос следующему ПО промежуточного слоя в конвейере.
  • Может выполнять работу до и после следующего промежуточного слоя в конвейере.

Для построения конвейера запросов используются делегаты запроса. Делегаты запросов обрабатывают каждый HTTP-запрос.

Делегаты запросов настраиваются с использованием методов расширения Run, Map и Use. Отдельный делегат запроса может быть указан в виде анонимного метода (называемого встроенным посредником) или определен в классе для повторного использования. Эти встроенные анонимные методы или повторно используемые классы называются компонентами ПО промежуточного слоя или ПО промежуточного слоя. Каждое ПО промежуточного слоя в конвейере запросов отвечает за вызов следующего ПО промежуточного слоя в конвейере или за короткое замыкание конвейера. Когда промежуточный слой прерывает выполнение, он называется терминальным промежуточным слоем, так как препятствует обработке запроса другими промежуточными слоями.

Дополнительные сведения о разнице между конвейерами запросов в ASP.NET Core и ASP.NET 4.x, а также о дополнительных примерах промежуточного ПО, см. в статье "Миграция модулей HTTP в промежуточное ПО ASP.NET Core".

Роль ПО промежуточного слоя по типу приложения

Серверный Blazor, Razor Страницы и MVC обрабатывают запросы браузера на сервере с помощью программного обеспечения промежуточного слоя. Инструкции, приведенные в этой статье, относятся к этим типам приложений.

Автономные Blazor WebAssembly приложения выполняются полностью на клиенте и не обрабатывают запросы с использованием промежуточного ПО. Руководство, приведенное в этой статье, не относится к автономным приложениям Blazor WebAssembly.

Анализ кода ПО промежуточного слоя

Дополнительные сведения об анализаторах платформы компилятора ASP.NET Core, которые проверяют код приложения на качество, см. в разделе "Анализ кода в ASP.NET Core приложениях".

Создайте middleware-конвейер с помощью WebApplication

Конвейер запросов ASP.NET Core состоит из последовательности делегатов запроса, вызываемых один за другим. На следующей схеме демонстрируется этот принцип. Поток выполнения показан черными стрелками.

Шаблон обработки запроса, показывающий поступление запроса, его обработку тремя ПО промежуточного слоя и выход ответа из приложения. Каждое ПО промежуточного слоя выполняет свою логику и передает запрос следующему ПО промежуточного слоя в операторе next(). После того как третье ПО промежуточного слоя обрабатывает запрос, запрос проходит через два предыдущих ПО промежуточного слоя в обратном порядке для дополнительной обработки после утверждения next(), а затем покидает приложение в качестве ответа клиенту.

Каждый из делегатов может выполнять операции до и после следующего делегата. Делегаты обработки исключений должны вызываться в начале конвейера, чтобы перехватывать исключения, возникающие на более поздних этапах.

Примечание.

Чтобы локально поэкспериментировать с примерами кода в этом разделе, создайте приложение ASP.NET Core с помощью шаблона проекта ASP.NET Core Empty . При использовании .NET CLI короткое имя шаблона — web (dotnet new web).

Простейшее приложение ASP.NET Core вызывает Run для настройки одного терминального промежуточного слоя, используя анонимную функцию-дегегат для обработки запросов без конвейера запросов.

В следующем примере :

  • Вызов функции RunExtensions.Run происходит по каждому запросу и записывает "Hello world!" в ответ.
  • Вызов WebApplication.Run в конце блока кода запускает приложение и блокирует вызывающий поток до завершения работы узла.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello world!");
});

app.Run();

Ответ при доступе к приложению в браузере по URL-адресу запуска:

Hello world!

Несколько делегатов запроса можно соединить в цепочку с помощью Use. Параметр next представляет следующий делегат в конвейере. Обычно можно выполнять действия до и после делегата next .

В следующем примере показано:

  • Два Use вызова, каждый из которых записывается в консоль:
    • Где может быть выполнена работа, которая может записать данные в ответ (context.Response, HttpResponse).
    • Где можно выполнить работу, которая не записывается в ответ, после вызова функции с параметром next.
  • Делегат терминального запроса с вызовом RunExtensions.Run, который отправляет "Hello world!" в ответ.
  • Последний Use вызов, который никогда не выполняется, так как он следует делегату Run запроса терминала.
  • Вызов WebApplication.Run в конце блока кода для запуска приложения и блокировки вызывающего потока до завершения работы узла.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    Console.WriteLine("Work that can write to the response. (1)");
    await next.Invoke(context);
    Console.WriteLine("Work that doesn't write to the response. (1)");
});

app.Use(async (context, next) =>
{
    Console.WriteLine("Work that can write to the response. (2)");
    await next.Invoke(context);
    Console.WriteLine("Work that doesn't write to the response. (2)");
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello world!");
});

app.Use(async (context, next) =>
{
    Console.WriteLine("This statement isn't reached. (3)");
    await next.Invoke(context);
    Console.WriteLine("This statement isn't reached. (3)");
});

app.Run();

В окне консоли приложения при запуске приложения:

Работа, которая может записывать данные в отклик. (1)
Работа, которая может записывать ответ. (2)
Работа, которая не записывает ответ. (2)
Работа, которая не выводит данные в ответ. (1)

Короткое замыкание конвейера запросов часто желательно, так как это позволяет избежать ненужных работ. Например, промежуточное ПО для статических файлов может выступать в качестве завершающего промежуточного ПО, обрабатывая запрос к статическому файлу и прерывая остальную часть конвейера. Промежуточные слои, добавленные в конвейер до завершающего промежуточного слоя, продолжают обрабатывать код после исполнения их next.Invoke инструкций. Если вы не планируете вызывать next.Invoke, так как ваша цель — завершение конвейера, используйте делегат Run вместо вызова метода расширения Use.

Не вызывайте next.Invoke во время или после отправки ответа клиенту. После запуска HttpResponse изменения приводят к исключению. Например, установка заголовков или кода состояния ответа вызывает исключение после запуска ответа. Запись в текст ответа после вызова next может:

  • Вызывает нарушение протокола, например запись большего количества байтов в ответ, чем декларированной длины содержимого ответа (Content-Length значение заголовка).
  • Искажайте формат тела документа, например, вставляя HTML-нижний колонтитул в CSS-файл.

Чтобы определить, запущен ли ответ, проверьте значение HasStarted.

Дополнительные сведения см. в разделе Промежуточное программное обеспечение с коротким замыканием после маршрутизации.

Run Делегат

Делегат Run не получает параметр next. Первый Run делегат всегда завершает конвейер. Run также является соглашением, и некоторые из промежуточных программ могут предоставлять методы Run, которые выполняются в конце конвейера.

Все делегаты Use или Run, следующие за первым делегатом Run, не будут вызваны.

Разветвить конвейер промежуточного ПО

Map расширения используются как соглашение для разветвления конвейера обработки запросов. Map разветвляет конвейер обработки запросов на основе совпадений с заданным путем запроса. Если путь запроса начинается с заданного пути, данная ветвь выполняется.

В следующем примере HandleMap1 вызывается для запросов к /map1, и HandleMap2 вызывается для запросов к /map2.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1", HandleMap1);
app.Map("/map2", HandleMap2);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from the non-Map delegate!");
});

app.Run();

private static void HandleMap1(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map 1");
    });
}

private static void HandleMap2(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map 2");
    });
}

В следующей таблице показаны запросы и ответы с помощью предыдущего кода.

Запрос Ответ
/ Hello from the non-Map delegate.
/map1 Map 1
/map2 Map 2
/map3 Hello from the non-Map delegate.

Когда используется Map, соответствующие сегменты путей удаляются из HttpRequest.Path и добавляются к HttpRequest.PathBase для каждого запроса.

Map способен сопоставляться с несколькими сегментами одновременно:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1/segment1", HandleMultipleSegments);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from the non-Map delegate.");
});

app.Run();

private static void HandleMultipleSegments(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Processing '/map1/segment1'");
    });
}

В следующей таблице показаны запросы и ответы с помощью предыдущего кода.

Запрос Ответ
/ Hello from the non-Map delegate.
/map1/segment1 Processing '/map1/segment1'

Map поддерживает вложение:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Processing '/level1/level2a'");
        });
    });
    level1App.Map("/level2b", level2BApp => {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Processing '/level1/level2b'");
        });
    });
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from the non-Map delegate!");
});

app.Run();

В следующей таблице показаны запросы и ответы с помощью предыдущего кода.

Запрос Ответ
/ Hello from the non-Map delegate.
/level1/level2a Processing '/level1/level2a'
/level1/level2b Processing '/level1/level2b'

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 the non-Map delegate.");
});

app.Run();

private static void HandleBranch(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        var branchVer = context.Request.Query["branch"];
        await context.Response.WriteAsync($"Branch used = '{branchVer}'");
    });
}

В следующей таблице показаны запросы и ответы с помощью предыдущего кода.

Запрос Ответ
/ Hello from the non-Map delegate.
/?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 the 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.ToString());

        Console.WriteLine("Work that can write to the response.");
        await next.Invoke(context);
        Console.WriteLine("Work that doesn't write to the response.");
    });
}

В предыдущем примере ответ "Hello from the non-Map delegate." записывается для всех запросов. Если запрос содержит переменную строки запроса с именем "branch", его значение регистрируется до повторного подключения основного конвейера.

Создайте middleware-конвейер с помощью IApplicationBuilder

Конвейер запросов ASP.NET Core состоит из последовательности делегатов запроса, вызываемых один за другим. На следующей схеме демонстрируется этот принцип. Поток выполнения показан черными стрелками.

Шаблон обработки запроса, показывающий поступление запроса, его обработку тремя ПО промежуточного слоя и выход ответа из приложения. Каждое ПО промежуточного слоя выполняет свою логику и передает запрос следующему ПО промежуточного слоя в операторе next(). После того как третье ПО промежуточного слоя обрабатывает запрос, запрос проходит через два предыдущих ПО промежуточного слоя в обратном порядке для дополнительной обработки после утверждения next(), а затем покидает приложение в качестве ответа клиенту.

Каждый из делегатов может выполнять операции до и после следующего делегата. Делегаты обработки исключений должны вызываться в начале конвейера, чтобы перехватывать исключения, возникающие на более поздних этапах.

Простейшее приложение 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. Обычно действия можно выполнять как до, так и после следующего делегата, как показано в этом примере.

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.
});

Если делегат не передает запрос следующему делегату, это называется замыканием конвейера запросов. Короткое замыкание часто является предпочтительным, так как позволяет избежать ненужной работы. Например, промежуточное ПО для статических файлов может выступать в качестве завершающего промежуточного ПО, обрабатывая запрос к статическому файлу и прерывая остальную часть конвейера. Компоненты промежуточного слоя, добавленные в конвейер перед промежуточным слоем, завершающим обработку, продолжают обработку кода после своих команд next.Invoke. Примите во внимание следующее предупреждение о попытке записи в ответ, который уже был отправлен.

Предупреждение

Не вызывайте next.Invoke после отправки отклика клиенту. Изменения HttpResponse после начала отправки ответа приведут к возникновению исключения. Например, при задании заголовков и кода состояния возникает исключение. Запись в тело отклика после вызова next:

  • может вызвать нарушение протокола, например, при записи более установленного значения Content-Length;
  • может привести к нарушению формата тела. например, при записи нижнего колонтитула HTML в CSS-файл.

HasStarted удобно использовать для обозначения того, были ли отправлены заголовки или выполнена запись в тело.

Делегаты Run не получают параметр next. Первый делегат Run всегда является конечным и завершает конвейер. Run — это соглашение. Некоторые компоненты промежуточного слоя могут предоставлять методы Run[Middleware], которые выполняются в конце конвейера:

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

В предыдущем примере делегат Run записывает "Hello from 2nd delegate." в ответ и завершает конвейер. Если добавить другой делегат Use или Run после делегата Run, он не будет вызван.

Разветвить конвейер промежуточного ПО

Расширения 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.ToString());

            // 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, ее значение регистрируется до того, как будет выполнено повторное объединение с основным конвейером.

Порядок ПО промежуточного слоя

Порядок расположения промежуточного слоя в файле приложения Program определяет порядок их вызова при обработке запроса и обратный порядок при формировании ответа.

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

В следующих примерах показан порядок промежуточного слоя для типичных сценариев приложений. Каждый метод расширения посредствующего слоя WebApplicationBuilder раскрывается через пространство имен Microsoft.AspNetCore.Builder.

  1. Обработка исключений и ошибок
    • Когда приложение выполняется в Development среде, выполните следующие действия:
      • Промежуточное ПО для страницы исключений разработчика (UseDeveloperExceptionPage) сообщает об ошибках выполнения приложения.
      • Промежуточное программное обеспечение страницы ошибок базы данных (UseDatabaseErrorPage) сообщает об ошибках времени выполнения базы данных.
    • Когда приложение выполняется в Production среде, выполните следующие действия:
      • Промежуточное ПО обработчика исключений (UseExceptionHandler) перехватывает исключения, возникшие в следующих промежуточных слоях.
      • Промежуточный слой (middleware) протокола HSTS (HTTP Strict Transport Security) (UseHsts) добавляет заголовок Strict-Transport-Security.
  2. Промежуточное ПО для перенаправления HTTPS (UseHttpsRedirection) перенаправляет запросы с HTTP на HTTPS.
  3. Промежуточное ПО для статических файлов (при необходимости UseStaticFiles) возвращает статические файлы и обходит дальнейшую обработку запросов.
  4. Cookie Промежуточное программное обеспечение политики (UseCookiePolicy) обеспечивает соответствие приложения Общему регламенту защиты данных (GDPR) Евросоюза.
  5. Промежуточное ПО маршрутизации (UseRouting) для маршрутизации запросов.
  6. ПО промежуточного слоя проверки подлинности (UseAuthentication) пытается проверить подлинность пользователя, прежде чем предоставить ему доступ к защищенным ресурсам.
  7. ПО промежуточного слоя авторизации (UseAuthorization) разрешает пользователю доступ к защищенным ресурсам.
  8. Промежуточное программное обеспечение для защиты от подделки (UseAntiforgery) добавляет его в конвейер обработки UseAntiforgery, и его нужно разместить после вызовов UseAuthentication и UseAuthorization.
  9. Промежуточное программное обеспечение сеанса (Razor только страницы и MVC UseSession) устанавливает и поддерживает состояние сеанса. Если приложение использует состояние сеанса, вызовите ПО промежуточного слоя сеанса после Cookie по промежуточного слоя политики и до Razor по промежуточного слоя Pages/MVC.
  10. Промежуточное программное обеспечение для маршрутизации конечных точек
  • MapRazorComponents Для добавления Razor конечных точек компонента в конвейер запросов.
  • MapRazorPages Для добавления Razor конечных точек Pages в конвейер запросов.
  • MapControllerRoute Для добавления конечных точек контроллера в конвейер запросов.

Типичный Blazor Web App конвейер промежуточного программного обеспечения:

app.UseWebAssemblyDebugging(); // Development environment with client-side rendering
app.UseMigrationsEndPoint(); // Development environment with ASP.NET Core Identity

app.UseExceptionHandler("/Error", createScopeForErrors: true); // Non-Development environment
app.UseHsts(); // Non-Development environment with HTTPS protocol

app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);

app.UseHttpsRedirection(); // With HTTPS protocol

app.UseAntiforgery();

app.MapStaticAssets();

app.MapRazorComponents<App>(); // With additional extension methods for render modes

app.MapAdditionalIdentityEndpoints(); // With ASP.NET Core Identity

app.Run();

Типичный конвейер промежуточного ПО Pages/MVC:

app.UseMigrationsEndPoint(); // Development environment with ASP.NET Core Identity

app.UseExceptionHandler("/Error"); // Non-Development environment
app.UseHsts(); // Non-Development environment with HTTPS protocol

app.UseHttpsRedirection(); // With HTTPS protocol

// app.UseCookiePolicy();
app.UseRouting(); // If not called, runs at the beginning of the pipeline by default
// app.UseRateLimiter();
// app.UseRequestLocalization();
// app.UseCors();

// app.UseAuthentication(); // Called internally for ASP.NET Core Identity
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();

app.MapStaticAssets();

app.MapControllerRoute(...); // For MVC controllers

app.MapRazorPages(); // For Razor Pages pages

app.MapControllers(); // With authentication in a Razor Pages app

app.Run();

В предыдущем коде:

  • Промежуточное ПО CORS (UseCors), промежуточное ПО проверки подлинности (UseAuthentication) и промежуточное ПО авторизации (UseAuthorization) должны быть в указанном порядке.
  • Промежуточное ПО CORS (UseCors) должно быть расположено перед промежуточным ПО кэширования ответов (UseResponseCaching), чтобы добавлять заголовки CORS для каждого запроса, включая кэшированные ответы. Для получения дополнительной информации см. раздел, в котором неясно, что UseCORS должен быть использован перед UseResponseCaching (dotnet/aspnetcore #23218.
  • ПО локализации запроса (UseRequestLocalization) должно размещаться перед любым посредником, который может проверить культуру запроса, например, посредником статических файлов (UseStaticFiles).
  • Промежуточный слой ограничения скорости (UseRateLimiter) должен вызываться после промежуточного слоя маршрутизации (UseRouting) при использовании конечных точек API с ограничением скорости. Например, если используется атрибут [EnableRateLimiting], промежуточное ПО для ограничения скорости должно быть вызвано после промежуточного ПО маршрутизации. При вызове только глобальных ограничителей, промежуточное программное обеспечение ограничения скорости может быть вызвано до промежуточного программного обеспечения маршрутизации.

В некоторых сценариях ПО промежуточного слоя имеет другой порядок. Например, кэширование и сжатие зависят от спецификации приложения. При выполнении следующих условий использование ЦП может быть сокращено путем кэширования сжатого ответа, но приложение может кэшировать различные представления ресурса, используя разные алгоритмы сжатия, такие как Gzip или Brotli.

app.UseResponseCaching();
app.UseResponseCompression();

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

Аутентификация не прерывает необработанные запросы. Хотя ПО промежуточного слоя проверки подлинности выполняет проверку подлинности, авторизация происходит после выбора Razor компонента в Blazor Web Appприложении MVC, страницы в Razor приложении Pages или контроллера и действия в приложении MVC.

На следующей схеме показан полный конвейер обработки запросов для приложений ASP.NET Core MVC и Razor Pages. Вы можете увидеть, как в стандартном приложении упорядочены существующие программы промежуточного слоя и где добавляются пользовательские программы промежуточного слоя. Вы можете полностью контролировать изменение порядка существующего ПО промежуточного слоя или внедрять новое пользовательское ПО промежуточного слоя для своих сценариев.

Конвейер ПО промежуточного слоя ASP.NET Core

Промежуточное ПО конечной точки на предыдущей схеме выполняет конвейер фильтра для соответствующего типа приложения — 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 Следующий код добавляет компоненты ПО промежуточного слоя для распространенных сценариев приложений:

  1. Обработка исключений и ошибок
    • Когда приложение выполняется в Development среде, выполните следующие действия:
      • Промежуточное ПО для страницы исключений разработчика (UseDeveloperExceptionPage) сообщает об ошибках выполнения приложения.
      • Промежуточное программное обеспечение страницы ошибок базы данных (UseDatabaseErrorPage) сообщает об ошибках времени выполнения базы данных.
    • Когда приложение выполняется в Production среде, выполните следующие действия:
      • Промежуточное ПО обработчика исключений (UseExceptionHandler) перехватывает исключения, возникшие в следующих промежуточных слоях.
      • Промежуточный слой (middleware) протокола HSTS (HTTP Strict Transport Security) (UseHsts) добавляет заголовок Strict-Transport-Security.
  2. Промежуточное ПО для перенаправления HTTPS (UseHttpsRedirection) перенаправляет запросы с HTTP на HTTPS.
  3. Промежуточное ПО для статических файлов (UseStaticFiles) возвращает статические файлы и прерывает дальнейшую обработку запросов.
  4. Программное обеспечение Middleware Cookie (UseCookiePolicy) обеспечивает соответствие приложения требованиям Общего регламента по защите данных (GDPR) ЕС.
  5. Промежуточное ПО маршрутизации (UseRouting) для маршрутизации запросов.
  6. ПО промежуточного слоя проверки подлинности (UseAuthentication) пытается проверить подлинность пользователя, прежде чем предоставить ему доступ к защищенным ресурсам.
  7. ПО промежуточного слоя авторизации (UseAuthorization) разрешает пользователю доступ к защищенным ресурсам.
  8. Промежуточное ПО сеанса (UseSession) устанавливает и поддерживает состояние сеанса. Если в приложении используется состояние сеанса, вызовите промежуточное ПО сеанса после промежуточного ПО политики Cookie и до промежуточного ПО MVC.
  9. Промежуточное ПО маршрутизации конечных точек (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();

На следующей схеме показан полный конвейер обработки запросов для приложений ASP.NET Core MVC и Razor Pages. Вы можете увидеть, как в стандартном приложении упорядочены существующие программы промежуточного слоя и где добавляются пользовательские программы промежуточного слоя. Вы можете полностью контролировать изменение порядка существующего ПО промежуточного слоя или внедрять новое пользовательское ПО промежуточного слоя для своих сценариев.

Конвейер ПО промежуточного слоя ASP.NET Core

Промежуточное ПО конечной точки на предыдущей схеме выполняет конвейер фильтра для соответствующего типа приложения — 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 Следующий код добавляет компоненты ПО промежуточного слоя для распространенных сценариев приложений:

  1. Обработка исключений и ошибок
    • Когда приложение выполняется в Development среде, выполните следующие действия:
      • Промежуточное ПО для страницы исключений разработчика (UseDeveloperExceptionPage) сообщает об ошибках выполнения приложения.
      • Промежуточное программное обеспечение страницы ошибок базы данных (UseDatabaseErrorPage) сообщает об ошибках времени выполнения базы данных.
    • Когда приложение выполняется в Production среде, выполните следующие действия:
      • Промежуточное ПО обработчика исключений (UseExceptionHandler) перехватывает исключения, возникшие в следующих промежуточных слоях.
      • Промежуточный слой (middleware) протокола HSTS (HTTP Strict Transport Security) (UseHsts) добавляет заголовок Strict-Transport-Security.
  2. Промежуточное ПО для перенаправления HTTPS (UseHttpsRedirection) перенаправляет запросы с HTTP на HTTPS.
  3. Промежуточное ПО для статических файлов (UseStaticFiles) возвращает статические файлы и прерывает дальнейшую обработку запросов.
  4. Программное обеспечение Middleware Cookie (UseCookiePolicy) обеспечивает соответствие приложения требованиям Общего регламента по защите данных (GDPR) ЕС.
  5. Промежуточное ПО маршрутизации (UseRouting) для маршрутизации запросов.
  6. ПО промежуточного слоя проверки подлинности (UseAuthentication) пытается проверить подлинность пользователя, прежде чем предоставить ему доступ к защищенным ресурсам.
  7. ПО промежуточного слоя авторизации (UseAuthorization) разрешает пользователю доступ к защищенным ресурсам.
  8. Промежуточное ПО сеанса (UseSession) устанавливает и поддерживает состояние сеанса. Если в приложении используется состояние сеанса, вызовите промежуточное ПО сеанса после промежуточного ПО политики Cookie и до промежуточного ПО MVC.
  9. Промежуточное ПО маршрутизации конечных точек (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();

На следующей схеме показан полный конвейер обработки запросов для приложений ASP.NET Core MVC и Razor Pages. Вы можете увидеть, как в стандартном приложении упорядочены существующие программы промежуточного слоя и где добавляются пользовательские программы промежуточного слоя. Вы можете полностью контролировать изменение порядка существующего ПО промежуточного слоя или внедрять новое пользовательское ПО промежуточного слоя для своих сценариев.

Конвейер ПО промежуточного слоя ASP.NET Core

Промежуточное ПО конечной точки на предыдущей схеме выполняет конвейер фильтра для соответствующего типа приложения — 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 добавляет компоненты ПО промежуточного слоя для распространенных сценариев приложений:

  1. Обработка исключений и ошибок
    • Когда приложение выполняется в Development среде, выполните следующие действия:
      • Промежуточное ПО для страницы исключений разработчика (UseDeveloperExceptionPage) сообщает об ошибках выполнения приложения.
      • ПО промежуточного слоя страниц ошибок базы данных отчитывает об ошибках среды выполнения базы данных.
    • Когда приложение выполняется в Production среде, выполните следующие действия:
      • Промежуточное ПО обработчика исключений (UseExceptionHandler) перехватывает исключения, возникшие в следующих промежуточных слоях.
      • Промежуточный слой (middleware) протокола HSTS (HTTP Strict Transport Security) (UseHsts) добавляет заголовок Strict-Transport-Security.
  2. Промежуточное ПО для перенаправления HTTPS (UseHttpsRedirection) перенаправляет запросы с HTTP на HTTPS.
  3. Промежуточное ПО для статических файлов (UseStaticFiles) возвращает статические файлы и прерывает дальнейшую обработку запросов.
  4. Программное обеспечение Middleware Cookie (UseCookiePolicy) обеспечивает соответствие приложения требованиям Общего регламента по защите данных (GDPR) ЕС.
  5. Промежуточное ПО маршрутизации (UseRouting) для маршрутизации запросов.
  6. ПО промежуточного слоя проверки подлинности (UseAuthentication) пытается проверить подлинность пользователя, прежде чем предоставить ему доступ к защищенным ресурсам.
  7. ПО промежуточного слоя авторизации (UseAuthorization) разрешает пользователю доступ к защищенным ресурсам.
  8. Промежуточное ПО сеанса (UseSession) устанавливает и поддерживает состояние сеанса. Если в приложении используется состояние сеанса, вызовите промежуточное ПО сеанса после промежуточного ПО политики Cookie и до промежуточного ПО MVC.
  9. Промежуточное ПО маршрутизации конечных точек (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.

Дополнительные сведения об одностраничных приложениях см. в руководствах по шаблонам проектов React и Angular.

UseCors и UseStaticFiles порядок

Дополнительные сведения о заказе UseCors и UseStaticFilesвключении запросов между источниками (CORS) см. в ASP.NET Core.

Порядок промежуточного программного обеспечения для пересылаемых заголовков

Запустите ПО промежуточного слоя перенаправленных заголовков перед другим ПО промежуточного слоя, чтобы убедиться, что ПО промежуточного слоя, использующее сведения о перенаправленных заголовках, может использовать значения заголовков для обработки. Чтобы запустить ПО промежуточного слоя перенаправленных заголовков после ПО промежуточного слоя для диагностики и обработки ошибок, ознакомьтесь с порядком выполнения ПО промежуточного слоя перенаправленных заголовков.

Встроенное посредническое ПО

Последний выпуск ASP.NET Core поставляется со следующим промежуточным программным обеспечением. Столбец стека пользовательского интерфейса указывает типичный стек пользовательского интерфейса где используется промежуточное программное обеспечение [All, Blazor Web App (BWA), Razor Pages и MVC (RP/MVC)]. В столбце Порядок указаны сведения о размещении ПО промежуточного слоя в конвейере обработки запросов и условия, в соответствии с которыми ПО промежуточного слоя может прервать обработку запроса. Если промежуточный слой замыкает конвейер обработки запроса и препятствует обработке запроса дальнейшими компонентами промежуточного слоя, он называется терминальным промежуточным слоем. Дополнительные сведения о коротком замыкании см. в разделе "Создание конвейера посреднического ПО"WebApplication

посредническое программное обеспечение Описание Стек пользовательского интерфейса Заказ
Защита от подделок Предоставляет поддержку защиты от подделки запросов. All После проверки подлинности и авторизации, перед переходом к конечным точкам.
Аутентификация Обеспечивает поддержку проверки подлинности. All До того как потребуется HttpContext.User. Конечная точка для обратных вызовов OAuth.
Авторизация Обеспечивает поддержку авторизации. All Непосредственно после ПО промежуточного слоя для проверки подлинности.
Политика Cookie Обеспечивает отслеживание согласия пользователей на хранение личных сведений и соблюдение минимальных стандартов для полей cookie, таких как secure и SameSite. All ** Перед промежуточным ПО, которое выдает файлы cookie. Например: Authentication, Session, MVC (TempData).
CORS Настраивает общий доступ к ресурсам независимо от источника. All Перед промежуточным ПО, использующим CORS. UseCors должен быть перед UseResponseCaching. Дополнительные сведения см. в статье Неочевидно, что UseCORS должно предшествовать UseResponseCaching (dotnet/aspnetcore #23218).
Страница со сведениями об исключении для разработчика Создает страницу со сведениями об ошибках, предназначенными только для использования в Development среде. All Перед промежуточным ПО, которое создает ошибки. Шаблоны проектов автоматически регистрируют это ПО промежуточного слоя в качестве первого ПО промежуточного слоя в конвейере при условии, что среда находится Development.
Диагностика Отдельное ПО промежуточного слоя, которое обеспечивает обработку исключений, предоставляет страницу исключений для разработчика, страницы состояния кода, веб-страницу по умолчанию для новых приложений. All Перед промежуточным слоем, который создает ошибки. Конечный пункт для обработки исключений или отображения веб-страницы по умолчанию для новых приложений.
переадресованные заголовки Пересылает заголовки прокси в текущий запрос. All Перед промежуточными слоями, использующими обновленные поля. Например: схема, узел, IP-адрес клиента, метод.
Проверка работоспособности Проверяет работоспособность приложения ASP.NET Core и его зависимостей, таких как проверка доступности базы данных. All Терминальным, если запрос соответствует терминальной точке проверки работоспособности.
Распространение заголовков Распространяет заголовки HTTP из входящего запроса на исходящие запросы HTTP-клиентов.
All
Ведение журнала HTTP Регистрирует запросы и отклики HTTP. All В начале потока промежуточного программного обеспечения.
Переопределение метода HTTP Позволяет входящему запросу POST переопределить метод. All Перед промежуточным ПО, использующим обновленный метод.
Перенаправление HTTPS Перенаправляет все запросы HTTP на HTTPS. All Перед промежуточным слоем, использующим URL-адрес.
Строгое обеспечение безопасности транспорта HTTP (HSTS) ПО промежуточного слоя для повышения безопасности, которое добавляет специальный заголовок ответа. All Перед отправкой ответов и после обработки промежуточным слоем, который изменяет запросы. Например: пересылка заголовков и переписывание URL.
MVC; Обрабатывает запросы с помощью MVC либо Razor Pages. RP/MVC Является конечным, если запрос соответствует маршруту.
OWIN Взаимодействие с приложениями, серверами и промежуточным программным обеспечением на основе OWIN. RP/MVC Конечный, если промежуточное программное обеспечение OWIN полностью обрабатывает запрос.
Кэширование выходных данных Предоставляет поддержку кэширования ответов на основе конфигурации. RP/MVC Перед программным обеспечением промежуточного слоя, требующим кэширования. UseRouting и UseCors должны прийти до UseOutputCache.
Кэширование ответов Обеспечивает поддержку для кэширования откликов. Для этого требуется участие клиента в работе. Используйте кэширование выходных данных для полного управления сервером. RP/MVC До промежуточного ПО, требующего кэширования. UseCors нужно использовать перед UseResponseCaching. Кэширование ответов обычно не полезно для приложений пользовательского интерфейса, таких как Pages, так как Razor браузеры обычно задают заголовки запросов, которые предотвращают кэширование. Кэширование выходных данных обеспечивает преимущества приложений пользовательского интерфейса.
Распаковка запросов Обеспечивает поддержку распаковки запросов. All Перед посредником, который считывает тело запроса.
Сжатие откликов Обеспечивает поддержку для сжатия откликов. All Перед промежуточным ПО, требующим сжатия.
Локализация запроса Обеспечивает поддержку локализации. All Перед локализацией конфиденциального ПО промежуточного слоя. Должно появляться после промежуточного ПО маршрутизации при использовании RouteDataRequestCultureProvider.
Таймауты запросов Предоставляет поддержку настройки времени ожидания запроса как в глобальном масштабе, так и для каждой конечной точки. All UseRequestTimeouts должен прийти после UseExceptionHandler, UseDeveloperExceptionPageи UseRouting.
Маршрутизация конечных точек. Определяет и ограничивает маршруты запросов. All Терминал для совпадающих маршрутов.
Спа Обрабатывает все запросы из этой точки в цепочке промежуточного ПО, возвращая страницу одностраничного приложения (SPA) по умолчанию. All Появляется поздно в конвейере, поэтому другие промежуточные программные обеспечения для обслуживания статических файлов, такие как действия MVC, имеют более высокий приоритет.
Сеанс Обеспечивает поддержку для управления пользовательскими сеансами. RP/MVC Перед промежуточным ПО, требующим сеансов.
Статический файл Обеспечивает поддержку для обработки статических файлов и просмотра каталогов. All Если запрос соответствует файлу, он является терминалом.
Переопределение URL-адреса Обеспечивает поддержку для переопределения URL-адресов и перенаправления запросов. All Перед промежуточным слоем, использующим URL-адрес.
Ведение журнала W3C Создает журналы доступа к серверу в расширенном формате файла журнала W3C. All В начале потока промежуточного программного обеспечения.
Blazor WebAssembly Отладки Отладка Blazor Web Appс, которые используют клиентскую отрисовку (CSR) во встроенных инструментах разработчика Chromium. BWA В начале потока промежуточного программного обеспечения.
WebSockets Обеспечивает поддержку протокола WebSockets. All Перед промежуточным ПО, необходимым для обработки запросов WebSocket.

Дополнительные ресурсы