ASP.NET Core Blazor 静态文件

注意

此版本不是本文的最新版本。 有关当前版本,请参阅本文.NET 9 版本。

警告

此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 有关当前版本,请参阅本文.NET 9 版本。

重要

此信息与预发布产品相关,相应产品在商业发布之前可能会进行重大修改。 Microsoft 对此处提供的信息不提供任何明示或暗示的保证。

有关当前版本,请参阅本文.NET 9 版本。

本文介绍用于提供静态文件的 Blazor 应用配置。

服务器端应用中的 Blazor 静态资产传送

提供静态资产由路由终结点约定或下表中所述的中间件管理。

功能 API .NET 版本 说明
映射静态资产路由终结点约定 MapStaticAssets .NET 9 或更高版本 优化静态资产到客户端的传输。
静态文件中间件 UseStaticFiles 所有 .NET 版本 在不优化 Map Static Assets 的情况下向客户端提供静态资产,但对于映射静态资产无法管理的一些任务非常有用。

通过在应用的请求处理管道中调用 MapStaticAssets 来配置映射静态资产,该管道执行以下操作:

映射静态资产通过组合生成和发布过程来收集应用中有关静态资产的信息来运行。 运行时库会利用此信息有效地向浏览器提供静态资产。

在大多数情况下,映射静态资产可以替换 UseStaticFiles 。 但是,映射静态资产经过优化,用于在生成和发布时从应用中的已知位置提供资产。 如果应用服务来自其他位置(如磁盘或嵌入资源)的资产,则应使用 UseStaticFiles

映射静态资产 (MapStaticAssets) 取代了在提供Blazor WebAssembly框架文件的应用中的调用UseBlazorFrameworkFiles,并且不需要显式调用UseBlazorFrameworkFiles,Blazor Web App因为调用时AddInteractiveWebAssemblyComponents会自动调用 API。

映射静态资产提供以下在调用 UseStaticFiles时不可用的好处:

  • 应用中所有资产的生成时压缩,包括 JavaScript (JS) 和样式表,但不包括已压缩的图像和字体资产。 Gzip (Content-Encoding: gz) 压缩在开发期间使用。 发布期间使用具有 Brotli (Content-Encoding: br) 压缩的 Gzip。
  • 使用每个文件的内容的 SHA-256 哈希的 Base64 编码字符串在生成时对所有资产应用指纹。 这可以防止重用旧版本的文件,即使已缓存了旧文件。 带有指纹的资产是使用 immutable 指令缓存的,这会导致浏览器在资产更改之前都不会再次请求该资产。 对于不支持 immutable 指令的浏览器,将添加 max-age 指令
    • 即使资产没有指纹,也会将文件的指纹哈希用作 ETag 值为每个静态资产生成基于内容的 ETags。 这可确保浏览器仅在文件内容发生更改时才会下载文件(或首次下载文件)。
    • 在内部,Blazor 将物理资产映射到其相应的指纹,这允许应用执行以下操作:
      • 查找自动生成的 Blazor 资产,例如 Blazor 的 CSS 隔离功能的 Razor 组件范围的 CSS,以及 JS 导入映射描述的 JS 资产。
      • 在页面 <head> 内容中生成链接标记以预加载资产。
  • Visual Studio 热重载开发测试期间:
    • 从资产中删除完整性信息,以避免在应用运行期间文件变更时出现问题。
    • 静态资产不会缓存,以确保浏览器始终能检索到当前内容。

启用交互式 WebAssembly 或交互式自动呈现模式后:

  • Blazor 会创建一个终结点,以将资源集合公开为 JS 模块。
  • 当 WebAssembly 组件呈现到页面中时,URL 将作为持久性组件状态发送到请求正文。
  • WebAssembly 启动期间,Blazor 会检索 URL、导入模块和调用函数来检索资产集合并在内存中重新构造。 URL 特定于内容并永久缓存,因此,每个用户只需为此开销成本付费一次,直到应用更新。
  • 资源集合还以人工可读的 URL (_framework/resource-collection.js) 公开,因此 JS 有权访问资源集合,以便实现增强的导航,或实现其他框架和第三方组件的功能。

映射静态资产不提供缩小或其他文件转换的功能。 缩小通常由自定义代码或第三方工具处理。

静态文件中间件()在映射静态资产(UseStaticFilesMapStaticAssets)无法处理的以下情况下非常有用:

有关详细信息,请参阅 ASP.NET Core 中的静态文件

使用映射静态资产路由终结点约定传递资产

本部分适用于服务器端 Blazor 应用。

资产通过 ComponentBase.Assets 属性传递,该属性解析给定资产的指纹 URL。 在以下示例中,Bootstrap、 Blazor 项目模板应用样式表(app.css)和 CSS 隔离样式表 (基于应用的命名空间 BlazorSample)链接在根组件(通常是 App 组件)Components/App.razor中:

<link rel="stylesheet" href="@Assets["bootstrap/bootstrap.min.css"]" />
<link rel="stylesheet" href="@Assets["app.css"]" />
<link rel="stylesheet" href="@Assets["BlazorSample.styles.css"]" />

导映射入

本部分适用于服务器端 Blazor 应用。

导入映射组件 (ImportMap) 表示一个导入映射元素(<script type="importmap"></script>),该元素定义模块脚本的导入映射。 导入映射组件放置在根组件(通常是App组件)Components/App.razor的内容中<head>

<ImportMap />

如果未将自定义 ImportMapDefinition 分配给导入映射组件,则会根据应用的资产生成导入映射。

以下示例演示自定义导入映射定义及其创建的导入映射。

基本导入映射:

new ImportMapDefinition(
    new Dictionary<string, string>
    {
        { "jquery", "https://cdn.example.com/jquery.js" },
    },
    null,
    null);

上述代码生成以下导入映射:

{
  "imports": {
    "jquery": "https://cdn.example.com/jquery.js"
  }
}

作用域内导入映射:

new ImportMapDefinition(
    null,
    new Dictionary<string, IReadOnlyDictionary<string, string>>
    {
        ["/scoped/"] = new Dictionary<string, string>
        {
            { "jquery", "https://cdn.example.com/jquery.js" },
        }
    },
    null);

上述代码生成以下导入映射:

{
  "scopes": {
    "/scoped/": {
      "jquery": "https://cdn.example.com/jquery.js"
    }
  }
}

具有完整性的导入映射:

new ImportMapDefinition(
    new Dictionary<string, string>
    {
        { "jquery", "https://cdn.example.com/jquery.js" },
    },
    null,
    new Dictionary<string, string>
    {
        { "https://cdn.example.com/jquery.js", "sha384-abc123" },
    });

上述代码生成以下导入映射:

{
  "imports": {
    "jquery": "https://cdn.example.com/jquery.js"
  },
  "integrity": {
    "https://cdn.example.com/jquery.js": "sha384-abc123"
  }
}

将导入映射定义 (ImportMapDefinition) 与 ImportMapDefinition.Combine 组合在一起。

导入从 ResourceAssetCollection 创建的映射,将静态资产映射到其相应的唯一 URL:

ImportMapDefinition.FromResourceCollection(
    new ResourceAssetCollection(
    [
        new ResourceAsset(
            "jquery.fingerprint.js",
            [
                new ResourceAssetProperty("integrity", "sha384-abc123"),
                new ResourceAssetProperty("label", "jquery.js"),
            ])
    ]));

上述代码生成以下导入映射:

{
  "imports": {
    "./jquery.js": "./jquery.fingerprint.js"
  },
  "integrity": {
    "jquery.fingerprint.js": "sha384-abc123"
  }
}

在应用的请求处理管道中调用 UseStaticFiles,将静态文件中间件配置为向客户端提供静态资产。 有关详细信息,请参阅 ASP.NET Core 中的静态文件

在 .NET 8 之前的版本中,Blazor 框架静态文件(如 Blazor 脚本)通过静态文件中间件提供。 在 .NET 8 及更高版本中,Blazor 框架静态文件通过终结点路由进行映射,而不再使用静态文件中间件。

本部分适用于所有 .NET 版本和 Blazor 应用。

下表汇总了 .NET 版本的静态文件 <link> href 格式。

有关放置静态文件链接的 <head> 内容的位置,请参阅 ASP.NET Core Blazor 项目结构。 还可以在单个 Razor 组件中使用 <HeadContent> 组件来提供静态资产链接。

有关放置静态文件链接的 <head> 内容的位置,请参阅 ASP.NET Core Blazor 项目结构

.NET 9 或更高版本

应用类型 href 示例
Blazor Web App @Assets["{PATH}"] <link rel="stylesheet" href="@Assets["app.css"]" />
<link href="@Assets["_content/ComponentLib/styles.css"]" rel="stylesheet" />
Blazor Server† @Assets["{PATH}"] <link href="@Assets["css/site.css"]" rel="stylesheet" />
<link href="@Assets["_content/ComponentLib/styles.css"]" rel="stylesheet" />
独立 Blazor WebAssembly {PATH} <link rel="stylesheet" href="css/app.css" />
<link href="_content/ComponentLib/styles.css" rel="stylesheet" />

.NET 8.x

应用类型 href 示例
Blazor Web App {PATH} <link rel="stylesheet" href="app.css" />
<link href="_content/ComponentLib/styles.css" rel="stylesheet" />
Blazor Server† {PATH} <link href="css/site.css" rel="stylesheet" />
<link href="_content/ComponentLib/styles.css" rel="stylesheet" />
独立 Blazor WebAssembly {PATH} <link rel="stylesheet" href="css/app.css" />
<link href="_content/ComponentLib/styles.css" rel="stylesheet" />

.NET 7.x 或更早版本

应用类型 href 示例
Blazor Server† {PATH} <link href="css/site.css" rel="stylesheet" />
<link href="_content/ComponentLib/styles.css" rel="stylesheet" />
托管 Blazor WebAssembly‡ {PATH} <link href="css/app.css" rel="stylesheet" />
<link href="_content/ComponentLib/styles.css" rel="stylesheet" />
Blazor WebAssembly {PATH} <link href="css/app.css" rel="stylesheet" />
<link href="_content/ComponentLib/styles.css" rel="stylesheet" />

†.NET 8 或更高版本支持 Blazor Server,但在 .NET 7 之后不再是项目模板。
‡建议在采用 .NET 8 或更高版本时将托管 Blazor WebAssembly 应用更新为 Blazor Web App。

静态 Web 资产项目模式

本部分适用于 Blazor Web App 的 .Client 项目。

Blazor Web App 的 .Client 项目中所需的 <StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode> 设置会将 Blazor WebAssembly 静态资产行为恢复为默认值,使该项目作为托管项目的一部分运行。 Blazor WebAssembly SDK (Microsoft.NET.Sdk.BlazorWebAssembly) 以特定方式配置静态 Web 资产,以便在“独立”模式下工作,服务器只需使用库的输出。 这不适用于 Blazor Web App,其中,应用的 WebAssembly 部分是主机的逻辑部分,必须表现得更像库。 例如,项目不公开样式捆绑包(例如 BlazorSample.Client.styles.css),而是仅向主机提供项目捆绑包,以便主机可以将其包括在自己的样式捆绑包中。

不支持更改 <StaticWebAssetProjectMode> 的值 (Default) 或从 .Client 项目中删除该属性。

Development 环境中的静态文件

本部分适用于服务器端静态文件。

在本地运行应用时,静态 Web 资产仅在 Development 环境中启用。 若要在本地开发和测试期间为 Development 以外的环境启用静态文件(例如 Staging),请在 Program 文件中的 WebApplicationBuilder 上调用 UseStaticWebAssets

警告

为确切环境调用 UseStaticWebAssets 以防止在生产环境中激活该功能,因为如果在生产环境中调用,该功能会从磁盘上的不同位置提供文件(而不是从项目提供)。 本部分中的示例通过调用 IsStaging 来检查 Staging 环境。

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

Blazor WebAssembly 资产的前缀

本部分适用于 Blazor Web App。

使用 WebAssemblyComponentsEndpointOptions.PathPrefix 终结点选项设置指示 Blazor WebAssembly 资产的前缀的路径字符串。 该路径必须对应于引用的 Blazor WebAssembly 应用程序项目。

endpoints.MapRazorComponents<App>()
    .AddInteractiveWebAssemblyRenderMode(options => 
        options.PathPrefix = "{PATH PREFIX}");

在上一示例中,{PATH PREFIX} 占位符是路径前缀,必须以正斜杠 (/) 开头。

在以下示例中,路径前缀设置为 /path-prefix

endpoints.MapRazorComponents<App>()
    .AddInteractiveWebAssemblyRenderMode(options => 
        options.PathPrefix = "/path-prefix");

静态 Web 资产基路径

本部分适用于独立的 Blazor WebAssembly 应用。

发布应用会将应用的静态资产,包括 Blazor 框架文件(_framework 文件夹资产),放置在已发布输出的根路径 (/) 中。 项目文件 (.csproj) 中指定的 <StaticWebAssetBasePath> 属性将基路径设置到非根路径:

<PropertyGroup>
  <StaticWebAssetBasePath>{PATH}</StaticWebAssetBasePath>
</PropertyGroup>

在前面的示例中,{PATH} 占位符是路径。

如果未设置 <StaticWebAssetBasePath> 属性,则独立应用发布在 /BlazorStandaloneSample/bin/Release/{TFM}/publish/wwwroot/

在前面的示例中,{TFM} 占位符是目标框架名字对象 (TFM)(例如 net6.0)。

如果独立 Blazor WebAssembly 应用中的 <StaticWebAssetBasePath> 属性将发布的静态资产路径设置为 app1,则发布的输出中应用的根路径为 /app1

在独立 Blazor WebAssembly 应用的项目文件(.csproj)中:

<PropertyGroup>
  <StaticWebAssetBasePath>app1</StaticWebAssetBasePath>
</PropertyGroup>

在发布的输出中,独立 Blazor WebAssembly 应用的路径为 /BlazorStandaloneSample/bin/Release/{TFM}/publish/wwwroot/app1/

在前面的示例中,{TFM} 占位符是目标框架名字对象 (TFM)(例如 net6.0)。

本部分适用于独立 Blazor WebAssembly 应用和托管的 Blazor WebAssembly 解决方案。

发布应用会将应用的静态资产,包括 Blazor 框架文件(_framework 文件夹资产),放置在已发布输出的根路径 (/) 中。 项目文件 (.csproj) 中指定的 <StaticWebAssetBasePath> 属性将基路径设置到非根路径:

<PropertyGroup>
  <StaticWebAssetBasePath>{PATH}</StaticWebAssetBasePath>
</PropertyGroup>

在前面的示例中,{PATH} 占位符是路径。

如果不设置 <StaticWebAssetBasePath> 属性,托管解决方案的客户端应用或独立应用将按照以下路径发布:

  • 托管的 Blazor WebAssembly 解决方案的 Server 项目中:/BlazorHostedSample/Server/bin/Release/{TFM}/publish/wwwroot/
  • 独立 Blazor WebAssembly 应用中:/BlazorStandaloneSample/bin/Release/{TFM}/publish/wwwroot/

如果托管的 Blazor WebAssembly 应用或独立 Blazor WebAssembly 应用的 Client 项目中的 <StaticWebAssetBasePath> 属性将发布的静态资产路径设置为 app1,则发布的输出中应用的根路径为 /app1

Client 应用的项目文件 (.csproj) 或独立 Blazor WebAssembly 应用的项目文件 (.csproj) 中:

<PropertyGroup>
  <StaticWebAssetBasePath>app1</StaticWebAssetBasePath>
</PropertyGroup>

在已发布的输出中:

  • 托管的 Blazor WebAssembly 解决方案的 Server 项目中客户端应用的路径:/BlazorHostedSample/Server/bin/Release/{TFM}/publish/wwwroot/app1/
  • 独立 Blazor WebAssembly 应用的路径:/BlazorStandaloneSample/bin/Release/{TFM}/publish/wwwroot/app1/

<StaticWebAssetBasePath> 属性最常用于控制单个托管部署中多个 Blazor WebAssembly 应用的已发布静态资产的路径。 有关详细信息,请参阅多个托管的 ASP.NET Core Blazor WebAssembly 应用。 该属性在独立 Blazor WebAssembly 应用中也有效。

在前面的示例中,{TFM} 占位符是目标框架名字对象 (TFM)(例如 net6.0)。

文件映射和静态文件选项

本部分适用于服务器端静态文件。

若要使用 FileExtensionContentTypeProvider 创建其他文件映射,或者要配置其他 StaticFileOptions,请使用以下方法之一。 在以下示例中,{EXTENSION} 占位符为文件扩展名,{CONTENT TYPE} 占位符为内容类型。 以下 API 的命名空间是 Microsoft.AspNetCore.StaticFiles

  • 使用 StaticFileOptions 通过 Program 中的依赖项注入 (DI) 来配置选项:

    var provider = new FileExtensionContentTypeProvider();
    provider.Mappings["{EXTENSION}"] = "{CONTENT TYPE}";
    
    builder.Services.Configure<StaticFileOptions>(options =>
    {
        options.ContentTypeProvider = provider;
    });
    
    app.UseStaticFiles();
    
  • StaticFileOptions 直接传递到 Program 文件中的 UseStaticFiles

    var provider = new FileExtensionContentTypeProvider();
    provider.Mappings["{EXTENSION}"] = "{CONTENT TYPE}";
    
    app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = provider });
    

若要使用 FileExtensionContentTypeProvider 创建其他文件映射,或者要配置其他 StaticFileOptions,请使用以下方法之一。 在以下示例中,{EXTENSION} 占位符为文件扩展名,{CONTENT TYPE} 占位符为内容类型。

  • 使用 StaticFileOptions 通过 Program 中的依赖项注入 (DI) 来配置选项:

    using Microsoft.AspNetCore.StaticFiles;
    
    ...
    
    var provider = new FileExtensionContentTypeProvider();
    provider.Mappings["{EXTENSION}"] = "{CONTENT TYPE}";
    
    builder.Services.Configure<StaticFileOptions>(options =>
    {
        options.ContentTypeProvider = provider;
    });
    

    此方法配置用于提供 Blazor 脚本的同一文件提供程序。 确保自定义配置不会干扰提供 Blazor 脚本。 例如,不要通过使用 provider.Mappings.Remove(".js") 配置提供程序来删除 JavaScript 文件的映射。

  • Program 文件中使用两次对 UseStaticFiles 的调用:

    • 使用 StaticFileOptions 在第一次调用中配置自定义文件提供程序。
    • 第二个中间件提供 Blazor 脚本,其使用 Blazor 框架提供的默认静态文件配置。
    using Microsoft.AspNetCore.StaticFiles;
    
    ...
    
    var provider = new FileExtensionContentTypeProvider();
    provider.Mappings["{EXTENSION}"] = "{CONTENT TYPE}";
    
    app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = provider });
    app.UseStaticFiles();
    
  • 可以使用 MapWhen 执行自定义静态文件中间件来避免在提供 _framework/blazor.server.js 时受到干扰:

    app.MapWhen(ctx => !ctx.Request.Path
        .StartsWithSegments("/_framework/blazor.server.js"),
            subApp => subApp.UseStaticFiles(new StaticFileOptions() { ... }));
    

从多个位置提供文件

本部分中的指南仅适用于 Blazor Web App。

若要使用 CompositeFileProvider 从多个位置服务文件:

示例:

在名为 AdditionalStaticAssets 的服务器项目中创建一个新文件夹。 将图像放入文件夹中。

将以下 using 语句添加到服务器项目的 Program 文件的顶部:

using Microsoft.Extensions.FileProviders;

在调用 UseStaticFiles 之前在服务器项目的 Program 文件中,添加以下代码:

var secondaryProvider = new PhysicalFileProvider(
    Path.Combine(builder.Environment.ContentRootPath, "AdditionalStaticAssets"));
app.Environment.WebRootFileProvider = new CompositeFileProvider(
    app.Environment.WebRootFileProvider, secondaryProvider);

在应用的 Home 组件 (Home.razor) 标记中,使用 <img> 标记引用图像:

<img src="{IMAGE FILE NAME}" alt="{ALT TEXT}" />

在上面的示例中:

  • {IMAGE FILE NAME} 占位符是图像文件名称。 如果图像文件位于 AdditionalStaticAssets 文件夹的根目录,则无需提供路径段。
  • {ALT TEXT} 占位符是图像备用文本。

运行应用。

其他资源