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


Статические файлы в ASP.NET Core

Note

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

Warning

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

Important

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

В текущем выпуске, см. версию .NET 9 этой статьи.

Статические файлы, также называемые статическими ресурсами, — это файлы в приложении ASP.NET Core, которые не создаются динамически. Вместо этого они предоставляются непосредственно клиентам по запросу, например, файлы HTML, CSS, изображения и JavaScript.

Руководство по Blazor статическим файлам, которое дополняет или заменяет рекомендации, приведенные в этой статье, см. раздел ASP.NET Core Blazor статические файлы.

Чтобы включить статическую обработку файлов в ASP.NET Core, вызовите MapStaticAssets.

По умолчанию статические файлы хранятся в корневом каталоге проекта. Каталог по умолчанию — {CONTENT ROOT}/wwwroot, где заполнитель {CONTENT ROOT} является корнем содержимого приложения. Только файлы в папке wwwroot будут адресируемыми, поэтому вам не нужно беспокоиться о остальной части кода.

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

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

Во время выполнения обнаруженные статические веб-ресурсы предоставляются как конечные точки с примененными заголовками HTTP, такими как заголовки кэширования и заголовки типов контента. Ресурс обслуживается один раз, пока файл не изменится или браузер очищает его кэш. ETag, Last-Modified и Content-Type задаются заголовки. Браузер не позволяет использовать устаревшие ресурсы после обновления приложения.

Доставка статических ресурсов основана на маршрутизации конечных точек, поэтому она работает с другими функциями с поддержкой конечных точек, например авторизацией. Он предназначен для работы со всеми платформами пользовательского интерфейса, включая Blazor, Razor Pages и MVC.

Статические ресурсы карты предоставляют следующие преимущества:

  • Сжатие во время сборки для всех ресурсов в приложении, включая JavaScript (JS) и таблицы стилей, но исключая ресурсы изображений и шрифтов, которые уже сжаты. Сжатие Gzip (Content-Encoding: gz) используется во время разработки. Сжатие Gzip и Brotli (Content-Encoding: br) используются во время публикации.
  • Отпечаток для всех ресурсов формируется во время сборки в виде строки в формате Base64, содержащей хэш SHA-256 каждого файла. Это предотвращает повторное использование старой версии файла, даже если старый файл кэшируется. Ресурсы с отпечатками кэшируются при помощи директивы immutable, что приводит к тому, что браузер больше не запрашивает ресурс до его изменения. Для браузеров, которые не поддерживают директиву immutable, добавляется директива max-age.
    • Даже если ресурсу не присвоен отпечаток, содержимое ETags создается для каждого статического ресурса с использованием хеша отпечатка файла в качестве значения ETag. Это гарантирует, что браузер загружает только файл, если его содержимое изменяется (или файл загружается в первый раз).
    • Внутри фреймворка сопоставляются физические активы с их уникальными идентификаторами, что позволяет приложению:
      • Найдите автоматически созданные ресурсы, например Razor компонент с областной видимостью CSS для Blazorфункции изоляции CSS и JS ресурсы, описанные JS в картах импорта.
      • Создайте теги ссылок в <head> содержимом страницы для предварительной загрузки ресурсов.

Статические ресурсы карты не предоставляют функции для минификации или других преобразований файлов. Минификация обычно обрабатывается пользовательским кодом или сторонними инструментами.

Чтобы включить статическую обработку файлов в ASP.NET Core, вызовите UseStaticFiles.

По умолчанию статические файлы хранятся в корневом каталоге проекта. Каталог по умолчанию — {CONTENT ROOT}/wwwroot, где заполнитель {CONTENT ROOT} является корнем содержимого приложения. Только файлы в папке wwwroot будут адресируемыми, поэтому вам не нужно беспокоиться о остальной части кода.

Во время выполнения статические веб-ресурсы возвращаются посредником статических файлов при запросе с применением заголовков модификации ресурсов и типа контента. ETag, Last-Modified и Content-Type задаются заголовки.

Промежуточное ПО для статических файлов обеспечивает обслуживание статических файлов и используется приложением при вызове UseStaticFiles в конвейере обработки запросов приложения. Файлы обслуживаются по пути, указанному в IWebHostEnvironment.WebRootPath или WebRootFileProvider, и по умолчанию из корневой веб-папки, обычно wwwroot.

Вы также можете обслуживать статические веб-ресурсы из ссылочных проектов и пакетов.

Изменение корневого каталога веб-сайта

Используйте метод UseWebRoot, если вы хотите изменить веб-корневой каталог. Дополнительные сведения см. в разделе ASP.NET Основные основы.

Запретить публикацию файлов в wwwroot, используя элемент проекта <Content> в файле проекта. Следующий пример запрещает публикацию содержимого в wwwroot/local и его вложенных каталогах:

<ItemGroup>
  <Content Update="wwwroot\local\**\*.*" CopyToPublishDirectory="Never" />
</ItemGroup>

Метод CreateBuilder устанавливает текущий каталог в качестве корневого каталога содержимого:

var builder = WebApplication.CreateBuilder(args);

Метод CreateDefaultBuilder устанавливает текущий каталог в качестве корневого каталога содержимого:

Host.CreateDefaultBuilder(args)

В конвейере обработки запросов после вызова UseHttpsRedirectionвызовите MapStaticAssets в конвейере обработки запросов приложения, чтобы включить обслуживание статических файлов из корневого веб-сайта приложения:

app.MapStaticAssets();

В конвейере обработки запросов после вызова UseHttpsRedirectionвызовите UseStaticFiles в конвейере обработки запросов приложения, чтобы включить обслуживание статических файлов из корневого веб-сайта приложения:

app.UseStaticFiles();

Статические файлы доступны по относительному пути от корневого каталога.

Чтобы получить доступ к изображению по wwwroot/images/favicon.pngадресу:

  • Формат URL-адреса: https://{HOST}/images/{FILE NAME}
    • Заполнитель {HOST} — это хост.
    • Заполнитель {FILE NAME} — это имя файла.
  • Примеры
    • Абсолютный URL-адрес: https://localhost:5001/images/favicon.png
    • Относительный URL-адрес от корня: images/favicon.png

В Blazor приложении images/favicon.png загружает изображение значка (favicon.png) из папки wwwroot/images приложения:

<link rel="icon" type="image/png" href="images/favicon.png" />

В Razor приложениях Pages и MVC символ ~ тильды указывает на корневой веб-сайт. В следующем примере ~/images/favicon.png загружается изображение значка favicon.png (wwwroot/images) из папки приложения:

<link rel="icon" type="image/png" href="~/images/favicon.png" />

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

Чтобы избежать выполнения всей цепочки обработки в промежуточном ПО после сопоставления статического ресурса, таково поведение UseStaticFiles, вызовите ShortCircuit на MapStaticAssets. Вызов ShortCircuit немедленно выполняет конечную точку и возвращает ответ, предотвращая выполнение другого промежуточного ПО для запросов на статические ресурсы.

app.MapStaticAssets().ShortCircuit();

Управление кэшированием статических файлов во время разработки

При запуске в среде разработки, например, во время разработки и тестирования с горячей перезагрузкой Visual Studio, фреймворк переопределяет заголовки кэша, чтобы предотвратить кэширование статических файлов браузерами. Это помогает гарантировать, что последняя версия файлов используется при изменении файлов, избегая проблем с устаревшим содержимым. В рабочей среде заданы правильные заголовки кэша, что позволяет браузерам кэшировать статические ресурсы должным образом.

Чтобы отключить это поведение, установите значение EnableStaticAssetsDevelopmentCachingtrue в файле параметров приложения среды разработки (appsettings.Development.json).

Статические файлы в нестандартных средахDevelopment

При локальном запуске приложения статические веб-ресурсы включены только в среде разработки. Чтобы включить статические файлы для сред, отличных от среды Разработка, во время локальной разработки и тестирования (например, в промежуточной (Staging) среде), вызовите функцию UseStaticWebAssets на WebApplicationBuilder.

Warning

Вызовите UseStaticWebAssets для точной среды, чтобы предотвратить активацию функции в рабочей среде, так как она обслуживает файлы из отдельных мест на диске вне проекта. Пример в этом разделе проверяет промежуточную среду с помощью IsStaging.

if (builder.Environment.IsStaging())
{
    builder.WebHost.UseStaticWebAssets();
}

Обслуживание файлов за пределами корневого каталога веб-сайта через IWebHostEnvironment.WebRootPath

Если IWebHostEnvironment.WebRootPath установлено в папку, отличную от wwwroot, отображаются следующие поведения по умолчанию:

  • В среде разработки статические ресурсы предоставляются из wwwroot, если ресурсы с одинаковым именем находятся как в wwwroot, так и в другой папке, назначенной для WebRootPath.
  • В любой среде, отличной от разработки, повторяющиеся статические ресурсы обслуживаются из WebRootPath папки.

Рассмотрим веб-приложение, созданное из пустого веб-шаблона:

  • Содержит файл Index.html в wwwroot и wwwroot-custom.
  • Файл Program обновляется для установки WebRootPath = "wwwroot-custom".
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    Args = args,
    WebRootPath = "wwwroot-custom"
});

По умолчанию для запросов к /:

  • В среде разработки возвращается wwwroot/Index.html.
  • В любой среде, отличной от разработки, wwwroot-custom/Index.html возвращается.

Чтобы гарантировать, что ресурсы из wwwroot-custom всегда возвращаются, используйте один из следующих подходов:

  • Удалите ресурсы с одинаковыми именами в wwwroot.

  • Установите ASPNETCORE_ENVIRONMENT в Properties/launchSettings.json на любое значение, кроме Development.

  • Отключите статические веб-ресурсы, установив значение <StaticWebAssetsEnabled> на false в файле проекта приложения. ПРЕДУПРЕЖДЕНИЕ: Отключение статических веб-ресурсов отключает Razor библиотеки классов.

  • Добавьте следующий XML-код в файл проекта:

    <ItemGroup>
      <Content Remove="wwwroot\**" />
    </ItemGroup>
    

Следующий код обновляет WebRootPath на значение, отличное от уровня разработки (Staging), гарантируя, что повторяющееся содержимое будет возвращено из wwwroot-custom вместо wwwroot.

var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    Args = args,
    EnvironmentName = Environments.Staging,
    WebRootPath = "wwwroot-custom"
});

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

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

Промежуточное программное обеспечение для обработки статических файлов включается в обработку запросов, когда UseStaticFiles вызывается в конвейере обработки запросов приложения, как правило, после добавления конвенций конечных точек статических ресурсов (MapStaticAssets).

Конвенции конечных точек статических ресурсов карты применяются в приложениях, рассчитанных на .NET 9 или более поздние версии. Промежуточное ПО для обработки статических файлов необходимо использовать в приложениях, предназначенных для версий .NET, предшествующих .NET 9.

Промежуточное ПО для статических файлов обслуживает статические файлы, но оно не обеспечивает тот же уровень оптимизации, что и соглашения об конечных точках распределения статических ресурсов. Функции сжатия и идентификации конвенций конечных точек Map Static Assets недоступны, если полагаться только на ПО промежуточного слоя статических файлов.

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

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

Обслуживание файлов за пределами корневого каталога веб-сайта через UseStaticFiles

Рассмотрим следующую иерархию каталогов со статическими файлами, находящимися за пределами корневого каталога приложения в папке с именем ExtraStaticFiles:

  • wwwroot
    • css
    • images
    • js
  • ExtraStaticFiles
    • images
      • red-rose.jpg

Запрос может получить доступ к red-rose.jpg, настроив новый экземпляр промежуточного программного обеспечения для статических файлов.

Пространства имен для следующего API:

using Microsoft.Extensions.FileProviders;

В конвейере обработки запросов после существующего вызова MapStaticAssets (.NET 9 или более поздней версии) или UseStaticFiles (.NET 8 или более ранней версии):

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles")),
    RequestPath = "/static-files"
});

В приведенном выше коде ExtraStaticFiles иерархия каталогов предоставляется публично через static-files сегмент URL-адреса. Запрос к https://{HOST}/StaticFiles/images/red-rose.jpg, где заполнитель {HOST} — это узел, сервирует red-rose.jpg файл.

Следующая разметка ссылается на ExtraStaticFiles/images/red-rose.jpg:

<img src="static-files/images/red-rose.jpg" alt="A red rose" />

В предыдущем примере нотация с косой чертой поддерживается в Razor представлениях Pages и MVC,src="~/StaticFiles/images/red-rose.jpg" а не для Razor компонентов в Blazor приложениях.

Раздача файлов из нескольких расположений

Руководство в этом разделе относится к приложениям Razor Pages и MVC. Рекомендации, применимые к s, см. в разделе статических файлов ASP.NET Core.

Рассмотрим следующую разметку, отображающую логотип компании:

<img src="~/logo.png" asp-append-version="true" alt="Company logo">

Разработчик намерен использовать вспомогательный элемент тега изображения для добавления версии и обслуживания файла из настраиваемого расположения, папки с именем ExtraStaticFiles.

В следующем примере вызываются вызовы MapStaticAssets для обслуживания файлов из wwwroot и UseStaticFiles для обслуживания файлов из ExtraStaticFiles:

В конвейере обработки запросов после существующего вызова MapStaticAssets (.NET 9 или более поздней версии) или UseStaticFiles (.NET 8 или более ранней версии):

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles"))
});

В следующем примере два раза вызывается UseStaticFiles для обслуживания файлов из обоих wwwroot и ExtraStaticFiles.

В конвейере обработки запросов после существующего вызова UseStaticFiles:

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles"))
});

С помощью предыдущего кода файл ExtraStaticFiles/logo.png отображается. Однако Вспомогательный элемент тега изображения (AppendVersion) не применяется, так как он зависит от WebRootFileProvider, который не был обновлён для включения папки ExtraStaticFiles.

Следующий код обновляет WebRootFileProvider для включения папки ExtraStaticFiles с помощью CompositeFileProvider. Это позволяет вспомогательному элементу тега изображения применять версию к изображениям в папке ExtraStaticFiles .

Пространство имен для следующего API:

using Microsoft.Extensions.FileProviders;

В конвейере обработки запросов до существующего вызова MapStaticAssets (.NET 9 или более поздней версии) или UseStaticFiles (.NET 8 или более ранней версии):

var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
    Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles"));

var compositeProvider = new CompositeFileProvider(webRootProvider, newPathProvider);

app.Environment.WebRootFileProvider = compositeProvider;

В качестве значений UseStaticFiles и UseFileServer по умолчанию используется поставщик файлов, указывающий на wwwroot. Вы можете предоставить дополнительные экземпляры UseStaticFiles и UseFileServer с другими поставщиками файлов для передачи файлов из других местоположений. Дополнительные сведения см. в разделе UseStaticFiles, который по-прежнему необходим в UseFileServer для wwwroot (dotnet/AspNetCore.Docs #15578).

Установка заголовков HTTP-ответов

Используется StaticFileOptions для задания заголовков ответа HTTP. Помимо настройки промежуточного ПО для обслуживания статических файлов, следующий код задаёт значение заголовку 604,800 секунд (одна неделя).

Пространства имен для следующего API:

using Microsoft.AspNetCore.Http;

В конвейере обработки запросов после существующего вызова MapStaticAssets (.NET 9 или более поздней версии) или UseStaticFiles (.NET 8 или более ранней версии):

app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        ctx.Context.Response.Headers.Append(
            "Cache-Control", "public, max-age=604800");
    }
});

Большая коллекция ресурсов

При работе с большими коллекциями ресурсов, то есть примерно 1000 или более шт., рекомендуется использовать пакетировщик для сокращения общего количества ресурсов, обслуживаемых приложением, или для объединения MapStaticAssets с UseStaticFiles.

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

Если вы не используете объединение, мы рекомендуем объединить его с MapStaticAssets и UseStaticFiles. В следующем примере демонстрируется подход.

В файле проекта (.csproj) свойство MSBuild StaticWebAssetEndpointExclusionPattern используется для фильтрации конечных точек из окончательного манифеста для MapStaticAssets. Исключенные файлы обрабатываются UseStaticFiles и не пользуются преимуществами сжатия, кэширования и хеширования.

При задании значения StaticWebAssetEndpointExclusionPattern, сохраните $(StaticWebAssetEndpointExclusionPattern), чтобы сохранить шаблон исключения платформы по умолчанию. Добавьте дополнительные шаблоны в списке, разделенном точкой с запятой.

В следующем примере паттен исключения добавляет статические файлы в lib/icons папку, которая представляет гипотетический пакет значков:

<StaticWebAssetEndpointExclusionPattern>
  $(StaticWebAssetEndpointExclusionPattern);lib/icons/**
</StaticWebAssetEndpointExclusionPattern>

После обработки промежуточного ПО перенаправления HTTPS в файле app.UseHttpsRedirection();:

  • Вызов UseStaticFiles для обработки исключенных файлов (lib/icons/**) и других файлов, не охваченных MapStaticAssets.
  • Вызовите MapStaticAssets после UseStaticFiles, чтобы обработать критически важные файлы приложения (CSS, JS, изображения).
app.UseStaticFiles();

app.UseAuthorization();

app.MapStaticAssets();

Авторизация статических файлов

Когда приложение принимает политику резервной авторизации, авторизация требуется для всех запросов, которые явно не указывают политику авторизации, включая запросы статических файлов после обработки запросов по промежуточного слоя авторизации. Разрешить анонимный доступ к статическим файлам путем применения AllowAnonymousAttribute к построителю конечных точек для статических файлов:

app.MapStaticAssets().Add(endpointBuilder => 
    endpointBuilder.Metadata.Add(new AllowAnonymousAttribute()));

Когда приложение принимает политику резервной авторизации, авторизация требуется для всех запросов, которые явно не указывают политику авторизации, включая запросы статических файлов после обработки запросов по промежуточного слоя авторизации. Шаблоны ASP.NET Core разрешают анонимный доступ к статическим файлам, вызывая UseStaticFiles перед вызовом UseAuthorization. Большинство приложений используют этот шаблон. Когда промежуточное ПО для работы со статическими файлами вызывается перед промежуточным ПО для авторизации:

  • для статических файлов не выполняются проверки авторизации;
  • Статические файлы, обслуживаемые промежуточным ПО для статических файлов, такие как те в веб-корневом каталоге (как правило, wwwroot), являются общедоступными.

Для обслуживания статических файлов на основе авторизации:

  • Убедитесь, что приложение задает резервную политику авторизации , чтобы требовать прошедших проверку подлинности пользователей.
  • Сохраните статический файл за пределами корневого веб-сайта приложения.
  • После вызова UseAuthorization, вызовите UseStaticFiles, указав путь к папке статических файлов за пределами корневого каталога веб-сайта.

Пространства имен для следующего API:

using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.FileProviders;

Регистрация службы:

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

В конвейере обработки запросов после вызова UseAuthorization:

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "SecureStaticFiles")),
    RequestPath = "/static-files"
});

Пространства имен для следующего API:

using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.FileProviders;

В Startup.ConfigureServices:

services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

В Startup.Configure после вызова UseAuthorization:

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.ContentRootPath, "SecureStaticFiles")),
    RequestPath = "/static-files"
});

В приведенном выше коде политика резервной авторизации требует проверки подлинности пользователей. Конечные точки, такие как контроллеры и Razor страницы, которые указывают собственные требования к авторизации, не используют политику резервной авторизации. Например, Razor страницы, контроллеры или методы действий с [AllowAnonymous] или [Authorize(PolicyName="MyPolicy")] используют примененный атрибут авторизации вместо резервной политики авторизации.

RequireAuthenticatedUser добавляет DenyAnonymousAuthorizationRequirement к текущему экземпляру, что обеспечивает проверку подлинности текущего пользователя.

Статические ресурсы, хранящиеся в корневом каталоге веб-приложения, доступны для общего пользования, так как промежуточное ПО статических файлов (UseStaticFiles) вызывается по умолчанию перед UseAuthorization. Статические ресурсы в папке SecureStaticFiles требуют проверки подлинности.

Альтернативный подход к обработке файлов на основе авторизации:

  • Храните файлы за пределами корневого веб-каталога и любого доступного каталога для промежуточного слоя статических файлов.
  • Обслуживайте файлы через метод действия, к которому применяется авторизация, и который возвращает объект FileResult.

Razor На странице (Pages/BannerImage.cshtml.cs):

public class BannerImageModel : PageModel
{
    private readonly IWebHostEnvironment _env;

    public BannerImageModel(IWebHostEnvironment env) => _env = env;

    public PhysicalFileResult OnGet()
    {
        var filePath = Path.Combine(
            _env.ContentRootPath, "SecureStaticFiles", "images", "red-rose.jpg");

        return PhysicalFile(filePath, "image/jpeg");
    }
}

С контроллера (Controllers/HomeController.cs):

[Authorize]
public IActionResult BannerImage()
{
    var filePath = Path.Combine(
        _env.ContentRootPath, "SecureStaticFiles", "images", "red-rose.jpg");

    return PhysicalFile(filePath, "image/jpeg");
}

Для предыдущего подхода требуется страница или конечная точка для каждого файла.

В следующем примере конечной точки маршрута возвращаются файлы для прошедших проверку подлинности пользователей.

В файле Program:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AuthenticatedUsers", b => b.RequireAuthenticatedUser());
});

...

app.MapGet("/files/{fileName}", IResult (string fileName) => 
{
    var filePath = GetOrCreateFilePath(fileName);

    if (File.Exists(filePath))
    {
        return TypedResults.PhysicalFile(filePath, fileName);
    }

    return TypedResults.NotFound("No file found with the supplied file name");
})
.WithName("GetFileByName")
.RequireAuthorization("AuthenticatedUsers");

Следующий пример конечной точки маршрута отправляет файлы для прошедших проверку подлинности пользователей в роли администратора ("admin").

В файле Program:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminsOnly", b => b.RequireRole("admin"));
});

...

// IFormFile uses memory buffer for uploading. For handling large 
// files, use streaming instead. See the *File uploads* article
// in the ASP.NET Core documentation:
// https://learn.microsoft.com/aspnet/core/mvc/models/file-uploads
app.MapPost("/files", async (IFormFile file, LinkGenerator linker, 
    HttpContext context) =>
{
    // Don't rely on the value in 'file.FileName', as it's only metadata that can 
    // be manipulated by the end-user. Consider the 'Utilities.IsFileValid' method 
    // that takes an 'IFormFile' and validates its signature within the 
    // 'AllowedFileSignatures'.

    var fileSaveName = Guid.NewGuid().ToString("N") + 
        Path.GetExtension(file.FileName);
    await SaveFileWithCustomFileName(file, fileSaveName);

    context.Response.Headers.Append("Location", linker.GetPathByName(context, 
        "GetFileByName", new { fileName = fileSaveName}));

    return TypedResults.Ok("File Uploaded Successfully!");
})
.RequireAuthorization("AdminsOnly");

В Startup.ConfigureServices:

services.AddAuthorization(options =>
{
    options.AddPolicy("AuthenticatedUsers", b => b.RequireAuthenticatedUser());
});

В Startup.Configure:

app.MapGet("/files/{fileName}", IResult (string fileName) => 
{
    var filePath = GetOrCreateFilePath(fileName);

    if (File.Exists(filePath))
    {
        return TypedResults.PhysicalFile(filePath, fileName);
    }

    return TypedResults.NotFound("No file found with the supplied file name");
})
.WithName("GetFileByName")
.RequireAuthorization("AuthenticatedUsers");

Следующий код отправляет файлы для прошедших проверку подлинности пользователей в роли администратора ("admin").

В Startup.ConfigureServices:

services.AddAuthorization(options =>
{
    options.AddPolicy("AdminsOnly", b => b.RequireRole("admin"));
});

В Startup.Configure:

// IFormFile uses memory buffer for uploading. For handling large 
// files, use streaming instead. See the *File uploads* article
// in the ASP.NET Core documentation:
// https://learn.microsoft.com/aspnet/core/mvc/models/file-uploads
app.MapPost("/files", async (IFormFile file, LinkGenerator linker, 
    HttpContext context) =>
{
    // Don't rely on the value in 'file.FileName', as it's only metadata that can 
    // be manipulated by the end-user. Consider the 'Utilities.IsFileValid' method 
    // that takes an 'IFormFile' and validates its signature within the 
    // 'AllowedFileSignatures'.

    var fileSaveName = Guid.NewGuid().ToString("N") + 
        Path.GetExtension(file.FileName);
    await SaveFileWithCustomFileName(file, fileSaveName);

    context.Response.Headers.Append("Location", linker.GetPathByName(context, 
        "GetFileByName", new { fileName = fileSaveName}));

    return TypedResults.Ok("File Uploaded Successfully!");
})
.RequireAuthorization("AdminsOnly");

Просмотр каталогов

Просмотр каталогов позволяет просматривать список каталогов в указанных каталогах.

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

Включите просмотр каталогов с помощью следующего API:

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

  • Папка images в корне приложения содержит изображения для просмотра каталогов.
  • Путь запроса для просмотра изображений /DirectoryImages.
  • Вызов UseStaticFiles и настройка FileProviderStaticFileOptions позволяет отображать ссылки браузера на отдельные файлы.

Пространства имен для следующего API:

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

Регистрация службы:

builder.Services.AddDirectoryBrowser();

В конвейере обработки запросов после существующего вызова MapStaticAssets (.NET 9 или более поздней версии) или UseStaticFiles (.NET 8 или более ранней версии):

var fileProvider = new PhysicalFileProvider(
    Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/DirectoryImages";

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

Пространства имен для следующего API:

using Microsoft.Extensions.FileProviders;
using System.IO;

В Startup.ConfigureServices:

services.AddDirectoryBrowser();

В Startup.Configure после существующего вызова UseStaticFiles:

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/DirectoryImages"
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/DirectoryImages"
});

Предыдущий код позволяет просматривать wwwroot/images папку с помощью URL-адреса https://{HOST}/DirectoryImages со ссылками на каждый файл и папку, где {HOST} заполнитель является узлом.

AddDirectoryBrowser добавляет службы, необходимые для ПО промежуточного слоя просмотра каталогов, в том числе HtmlEncoder. Эти службы могут быть добавлены другими звонками, например AddRazorPages, но мы рекомендуем вызывать AddDirectoryBrowser для обеспечения добавления служб.

Обслуживание документов по умолчанию

Страница по умолчанию является для пользователей отправной точкой на веб-сайте. Чтобы предоставить файл по умолчанию из wwwroot, не требуя, чтобы URL-адрес запроса включал имя файла, вызовите метод UseDefaultFiles.

UseDefaultFiles — это средство переопределения URL-адресов, которое не обслуживает файл. В конвейере обработки запросов перед существующим вызовом MapStaticAssets (.NET 9 или более поздней версии) или UseStaticFiles (.NET 8 или более ранней версии):

app.UseDefaultFiles();

При использовании UseDefaultFiles запросы к папке в wwwroot будут искать следующие файлы:

  • default.htm
  • default.html
  • index.htm
  • index.html

Первый найденный файл из списка будет обслужен, как если бы запрос включал имя файла. URL-адрес в браузере будет соответствовать запрошенному URI.

Следующий код изменяет имя default-document.htmlфайла по умолчанию на:

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("default-document.html");
app.UseDefaultFiles(options);

Объединение статических файлов, документов по умолчанию и просмотра каталогов

UseFileServer объединяет функции UseStaticFiles, UseDefaultFiles и при необходимости UseDirectoryBrowser.

В конвейере обработки запросов после существующего вызова MapStaticAssets (.NET 9 или более поздней версии) или UseStaticFiles (.NET 8 или более ранней версии) вызовите UseFileServer для активации обслуживания статических файлов и файла по умолчанию.

app.UseFileServer();

Просмотр каталогов не включен для предыдущего примера.

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

Регистрация службы:

builder.Services.AddDirectoryBrowser();

В конвейере обработки запросов после существующего вызова UseStaticFiles:

app.UseFileServer(enableDirectoryBrowsing: true);

В Startup.ConfigureServices:

services.AddDirectoryBrowser();

В Startup.Configure после существующего вызова UseStaticFiles:

app.UseFileServer(enableDirectoryBrowsing: true);

Для адреса узла (/) UseFileServer возвращает HTML-документ по умолчанию перед представлением страницы по умолчанию (Razor) или представлением MVC по умолчанию (Pages/Index.cshtml).

Пусть имеется следующая иерархия каталогов:

  • wwwroot
    • css
    • images
    • js
  • ExtraStaticFiles
    • images
      • logo.png
    • default.html

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

Пространства имен для следующего API:

using Microsoft.Extensions.FileProviders;

Регистрация службы:

builder.Services.AddDirectoryBrowser();

В конвейере обработки запросов после существующего вызова UseStaticFiles:

app.UseFileServer(new FileServerOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles")),
    RequestPath = "/static-files",
    EnableDirectoryBrowsing = true
});

Пространства имен для следующего API:

using Microsoft.Extensions.FileProviders;
using System.IO;

В Startup.ConfigureServices:

services.AddDirectoryBrowser();

В Startup.Configure после существующего вызова UseStaticFiles:

app.UseFileServer(new FileServerOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.ContentRootPath, "ExtraStaticFiles")),
    RequestPath = "/static-files",
    EnableDirectoryBrowsing = true
});

AddDirectoryBrowser должно вызываться, когда свойство EnableDirectoryBrowsing имеет значение true.

Используя предыдущую иерархию файлов и код, URL-адреса определяются, как показано в следующей таблице ( {HOST} заполнитель — хост).

URI Файл ответа
https://{HOST}/static-files/images/logo.png ExtraStaticFiles/images/logo.png
https://{HOST}/static-files ExtraStaticFiles/default.html

Если в каталоге ExtraStaticFiles нет файла с именем по умолчанию, https://{HOST}/static-files возвращает список содержимого каталога с кликабельными ссылками, где заполнителем {HOST} является хост.

UseDefaultFiles и UseDirectoryBrowser выполняют перенаправление на стороне клиента из целевого URI без / в конце в целевой URI с / в конце. Например, от https://{HOST}/static-files (без замыкающего /) до https://{HOST}/static-files/ (включает в себя замыкающий /). Относительные URL-адреса в каталоге ExtraStaticFiles недопустимы без завершающей косой черты (/), если не используется параметр RedirectToAppendTrailingSlash для DefaultFilesOptions.

Сопоставление расширений файлов с типами MIME

Note

Для инструкций, применимых к Blazor приложениям, см. раздел ASP.NET Core статические файлыBlazor.

Используйте FileExtensionContentTypeProvider.Mappings для добавления или изменения сопоставлений расширений файлов с типами контента MIME. В следующем примере несколько расширений файлов сопоставляются с известными типами MIME. Расширение .rtf заменяется и .mp4 удаляется:

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

...

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    ContentTypeProvider = provider
});

При наличии нескольких вариантов статических файлов, вы можете также задать поставщика с помощью StaticFileOptions:

var provider = new FileExtensionContentTypeProvider();

...

builder.Services.Configure<StaticFileOptions>(options =>
{
    options.ContentTypeProvider = provider;
});

app.UseStaticFiles();

В Startup.Configure:

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
using System.IO;

...

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/images",
    ContentTypeProvider = provider
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/images"
});

Дополнительные сведения см. в разделе "Типы контента MIME".

Нестандартные типы содержимого

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

Следующий код позволяет обслуживать неизвестные типы контента и отображать неизвестный файл в виде изображения:

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "image/png"
});

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

Warning

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

Предоставление манифеста настраиваемых статических файлов

Если staticAssetsManifestPath это nullтак, IHostEnvironment.ApplicationName используется для поиска манифеста. Кроме того, укажите полный путь к файлу манифеста. Если используется относительный путь, платформа выполняет поиск файла в файле AppContext.BaseDirectory.

Безопасность статических файлов

Warning

Использование UseDirectoryBrowser и UseStaticFiles может привести к утечке конфиденциальной информации. Настоятельно рекомендуется отключать просмотр каталогов в рабочей среде. Тщательно проверьте, просмотр каких каталогов разрешен посредством UseStaticFiles или UseDirectoryBrowser. Весь каталог и его подкаталоги становятся общедоступными. Храните файлы, предназначенные для общего доступа, в выделенных каталогах, таких как <content_root>/wwwroot. Отделите эти файлы от представлений MVC, Razor Pages, файлов конфигурации и т. д.

  • К URL-адресам содержимого, к которому предоставлен доступ методами UseDirectoryBrowser и UseStaticFiles, применяются те же требования по регистрозависимости и запрещенным символам, что и к базовой файловой системе. Например, Windows не чувствителен к регистру, а macOS и Linux чувствительны к регистру.

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

  • Выполните следующие шаги в диспетчере служб IIS для удаления обработчика статических файлов IIS на уровне сервера или веб-сайта:

    1. Перейдите к компоненту Модули.
    2. Выберите в списке модуль StaticFileModule.
    3. Нажмите кнопку Удалить в боковой панели Действия.

Warning

Если обработчик статических файлов IIS включен и модуль ASP.NET Core настроен неправильно, то статические файлы будут обслуживаться. Это происходит, например, если файл web.config не развернут.

  • Поместите файлы кода, включая .cs и .cshtmlвне корневого веб-сайта проекта приложения. Таким образом, в приложении создается логическое разделение между клиентским содержимым и серверным кодом. Это предотвращает утечку серверного кода.

Свойства MSBuild

В следующих таблицах показаны свойства и описания метаданных статических файлов MSBuild.

Недвижимость Description
EnableDefaultCompressedItems Активирует шаблоны сжатия по умолчанию для включения и исключения.
CompressionIncludePatterns Разделенный точкой с запятой список шаблонов файлов для сжатия.
CompressionExcludePatterns Разделенный точкой с запятой список шаблонов файлов для исключения из сжатия.
EnableDefaultCompressionFormats Включает форматы сжатия по умолчанию (Gzip и Brotli).
BuildCompressionFormats Форматы сжатия для использования во время сборки.
PublishCompressionFormats Форматы сжатия для использования во время публикации.
DisableBuildCompression Отключает сжатие во время сборки.
CompressDiscoveredAssetsDuringBuild Сжимает обнаруженные ресурсы во время сборки.
BrotliCompressionLevel Уровень сжатия для алгоритма Brotli.
StaticWebAssetBuildCompressAllAssets Сжимает все ресурсы во время сборки, а не только ресурсы, обнаруженные или вычисляемые во время сборки.
StaticWebAssetPublishCompressAllAssets Сжимает все ресурсы во время публикации, а не только ресурсы, обнаруженные или вычисляемые во время сборки.
Недвижимость Description
StaticWebAssetBasePath Базовый URL-путь для всех ресурсов в библиотеке.
StaticWebAssetsFingerprintContent Включает отпечаток содержимого для перебора кэша.
StaticWebAssetFingerprintingEnabled Включает функцию отпечатков пальцев для статических веб-ресурсов.
StaticWebAssetsCacheDefineStaticWebAssetsEnabled Включает кэширование для определений статических веб-элементов.
StaticWebAssetEndpointExclusionPattern Шаблон исключения конечных точек.
Группа номенклатур Description Метаданные
StaticWebAssetContentTypeMapping Сопоставляет шаблоны файлов с типами контента и заголовками кэша для конечных точек. Pattern, Cache
StaticWebAssetFingerprintPattern Определяет шаблоны применения отпечатков пальцев к статическим веб-ресурсам для перебора кэша. Pattern, Expression

Описания метаданных:

  • Pattern: шаблон glob, используемый для сопоставления файлов. В StaticWebAssetContentTypeMapping он сопоставляет файлы, чтобы определить их тип содержимого (например, *.js для файлов JavaScript). Файлы с несколькими расширениями, требующие специальной обработки отпечатков, идентифицируются для StaticWebAssetFingerprintPattern (например, *.lib.module.js).

  • Cache: указывает Cache-Control значение заголовка для соответствующего типа контента. Это управляет поведением кэширования браузера (например, max-age=3600, must-revalidate для файлов мультимедиа).

  • Expression: определяет, как отпечатки пальцев вставляются в имя файла. Значение по умолчанию — #[.{FINGERPRINT}], что обозначает вставку отпечатка пальца (заполнителя {FINGERPRINT}) перед расширением.

В следующем примере шаблон файла растрового изображения (.bmp) сопоставляется с типом контента image/bmp, а заполнитель {CACHE HEADER} представляет заголовок Cache-Control, используемый для конечных точек, не имеющих отпечатков пальцев.

<ItemGroup>
  <StaticWebAssetContentTypeMapping Include="image/bmp" Cache="{CACHE HEADER}" Pattern="*.bmp" />
</ItemGroup>

Параметры конфигурации среды выполнения

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

Ключ конфигурации Description
ReloadStaticAssetsAtRuntime Включает горячую перезагрузку статических ресурсов во время разработки: вместо версии манифеста, созданной во время сборки, подает измененные файлы веб-корня (wwwroot) (пересчитывает ETag, сжимает повторно при необходимости). Значение по умолчанию включено только при обслуживании манифеста сборки, если не указано явно.
DisableStaticAssetNotFoundRuntimeFallback Если true, подавляйте использование вспомогательной конечной точки, которая обслуживает недавно добавленные файлы, отсутствующие в манифесте сборки. Когда false отсутствует, резервная проверка наличия файла {**path} (GET/HEAD) выдаёт предупреждение и обслуживает файл с вычисленным ETag.
EnableStaticAssetsDevelopmentCaching При включении true сохраняются оригинальные Cache-Control заголовки в дескрипторах активов. Когда false присутствует или отсутствует, переписывает Cache-Control заголовки на no-cache, чтобы избежать агрессивного кэширования клиента во время разработки.
EnableStaticAssetsDevelopmentIntegrity При true этом сохраняются свойства целостности в дескрипторах активов. При наличии false или его отсутствии, удаляет любое свойство целостности, чтобы предотвратить несоответствия при изменении файлов во время разработки.

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