通过


ASP.NET Core Blazor 启动

注意

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

警告

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

本文介绍 Blazor 应用启动配置。

有关用于服务器端开发的 ASP.NET Core 应用配置的一般指南,请参阅 ASP.NET Core 中的配置

启动过程和配置

Blazor 启动过程可以通过 Blazor 脚本 (blazor.*.js) 自动异步完成,其中 * 占位符为:

  • web用于Blazor Web App.
  • server 用于 Blazor Server 应用。
  • webassembly用于Blazor WebAssembly应用。

Blazor 启动过程可以通过 Blazor 脚本 (blazor.*.js) 自动异步完成,其中 * 占位符为:

  • server适用于Blazor Server应用程序。
  • webassembly用于Blazor WebAssembly应用程序。

有关脚本的位置,请参阅 ASP.NET Core Blazor 项目结构

手动启动 Blazor 的步骤:

Blazor Web App:

  • autostart="false" 属性和值添加到 Blazor<script> 标记中。
  • 将调用 Blazor.start() 的脚本放置在 Blazor<script> 标记之后并放在结束的 </body> 标记内。
  • 将静态服务器端呈现(静态 SSR)选项置于 ssr 属性中。
  • 将服务器端 Blazor-SignalR 线路选项置于 circuit 属性中。
  • 将客户端 WebAssembly 选项置于 webAssembly 属性中。
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  ...
  Blazor.start({
    ssr: {
      ...
    },
    circuit: {
      ...
    },
    webAssembly: {
      ...
    }
  });
  ...
</script>

在前面的示例中,{BLAZOR SCRIPT} 占位符是 Blazor 脚本路径和文件名。 有关脚本的位置,请参阅 ASP.NET Core Blazor 项目结构

独立 Blazor WebAssembly 和 Blazor Server:

  • autostart="false" 属性和值添加到 Blazor<script> 标记中。
  • 将调用 Blazor.start() 的脚本放置在 Blazor<script> 标记之后并放在结束的 </body> 标记内。
  • 可以在 Blazor.start() 参数中提供其他选项。
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  ...
  Blazor.start({
    ...
  });
  ...
</script>

在前面的示例中,{BLAZOR SCRIPT} 占位符是 Blazor 脚本路径和文件名。 有关脚本的位置,请参阅 ASP.NET Core Blazor 项目结构

JavaScript 初始值设定项

JavaScript (JS) 初始值设定项在 Blazor 应用加载之前和之后执行逻辑。 JS 初始化器在以下场景中很有用:

  • 自定义 Blazor 应用的加载方式。
  • 在 Blazor 启动之前初始化库。
  • 配置 Blazor 设置。

JS 初始化器会在构建过程中被检测到并自动导入。 使用 JS 初始值设定项通常无需在使用 时Razor。

若要定义 JS 初始值设定项,请向项目添加名为 JS 的 {NAME}.lib.module.js 模块,其中 {NAME} 占位符是程序集名称、库名称或包标识符。 将文件放在项目的 Web 根目录中,通常为 wwwroot 文件夹。

对于 Blazor Web App:

  • beforeWebStart(options):在 Blazor Web App 启动之前调用。 例如,beforeWebStart 用于自定义加载过程、日志记录级别和其他选项。 接收 Blazor Web 选项 (options)。
  • afterWebStarted(blazor):在所有 beforeWebStart 承诺解决后调用。 例如,afterWebStarted 可用于注册 Blazor 事件侦听器和自定义事件类型。 Blazor 实例作为参数 (afterWebStarted) 传递给 blazor
  • beforeServerStart(options, extensions):在启动第一个服务器运行时之前调用。 接收 SignalR 路线启动选项 (options) 以及在发布期间添加的任何扩展 (extensions)。
  • afterServerStarted(blazor):在启动第一个交互式服务器运行时之后调用。
  • beforeWebAssemblyStart(options, extensions):在启动交互式 WebAssembly 运行时之前调用。 接收 Blazor 选项 (options) 以及在发布期间添加的任何扩展 (extensions)。 例如,选项可以指定使用自定义启动资源加载程序
  • afterWebAssemblyStarted(blazor):在启动交互式 WebAssembly 运行时之后调用。

注意

在 JS 中,默认情况下不会调用旧的 beforeStart 初始值设定项(afterStarted、Blazor Web App)。 可使用 enableClassicInitializers 选项启用旧版初始值设定项来运行。 但是,旧版初始化器的执行是不可预测的。

<script>
  Blazor.start({ enableClassicInitializers: true });
</script>

由于 .NET 8 和 9 (dotnet/aspnetcore #54049) 中的框架 bug,必须在调用 Blazor 或 beforeWebAssemblyStart(options, extensions) 时手动启动afterWebAssemblyStarted(blazor) 脚本。 如果服务器应用尚未使用 WebAssembly (Blazor) 配置手动启动 webAssembly: {...},请在服务器项目中使用以下内容更新 App 组件。

Components/App.razor中,删除现有 Blazor<script> 标记:

- <script src="_framework/blazor.web.js"></script>

<script> 标记替换为以下标记,这些标记使用 WebAssembly (Blazor) 配置手动启动 webAssembly: {...}

<script src="_framework/blazor.web.js" autostart="false"></script>
<script>
    Blazor.start({
        webAssembly: {}
    });
</script>

对于 Blazor Server、Blazor WebAssembly 和 Blazor Hybrid 应用:

  • beforeStart(options, extensions):在 Blazor 启动之前调用。 例如,beforeStart 用于自定义加载过程、日志记录级别以及其他特定于托管模型的选项。
    • 客户端 beforeStart 接收 Blazor 选项 (options) 以及在发布期间添加的任何扩展 (extensions)。 例如,选项可以指定使用自定义启动资源加载程序
    • 服务器端 beforeStart 接收 SignalR 电路启动选项 (options)。
    • BlazorWebView 中,不会传递任何选项。
  • afterStarted(blazor):在 Blazor 准备好从 JS 接收调用后调用。 例如,afterStarted 用于通过进行 JS 互操作调用并注册自定义元素来初始化库。 Blazor 实例作为参数 (afterStarted) 传递给 blazor

新增 .NET WebAssembly 运行时调用功能:

  • onRuntimeConfigLoaded(config):在下载启动配置时调用。 允许应用在运行时启动前(参数是来自 MonoConfigdotnet.d.ts)修改参数(配置):

    export function onRuntimeConfigLoaded(config) {
      // Sample: Enable startup diagnostic logging when the URL contains 
      // parameter debug=1
      const params = new URLSearchParams(location.search);
      if (params.get("debug") == "1") {
        config.diagnosticTracing = true;
      }
    }
    
  • onRuntimeReady({ getAssemblyExports, getConfig }):在 .NET WebAssembly 运行时启动后调用(参数是来自 RuntimeAPIdotnet.d.ts):

    export function onRuntimeReady({ getAssemblyExports, getConfig }) {
      // Sample: After the runtime starts, but before Main method is called, 
      // call [JSExport]ed method.
      const config = getConfig();
      const exports = await getAssemblyExports(config.mainAssemblyName);
      exports.Sample.Greet();
    }
    

这两个回调都可以返回一个 Promise,并会在启动继续之前等待该承诺。

对于文件名:

  • 如果 JS 初始值设定项用作项目中的静态资产,请使用格式 {ASSEMBLY NAME}.lib.module.js,其中 {ASSEMBLY NAME} 占位符是应用的程序集名称。 例如,对于程序集名称为 BlazorSample.lib.module.js 的项目,将文件命名为 BlazorSample。 将文件放在应用的 wwwroot 文件夹中。
  • 如果从 RCL 使用 JS 初始化程序,请使用格式 {LIBRARY NAME/PACKAGE ID}.lib.module.js,其中 {LIBRARY NAME/PACKAGE ID} 占位符是项目的库名称或包标识符(库的项目文件中的 <PackageId> 值)。 例如,对于包标识符为 RazorClassLibrary1.lib.module.js 的 RCL,将文件命名为 RazorClassLibrary1。 将文件放在库的 wwwroot 文件夹中。

对于 Blazor Web App:

下面的示例展示了通过将脚本追加到 JS 和 Blazor Web App 中的 <head>,在 beforeWebStart 启动之前和之后加载自定义脚本的 afterWebStarted 初始值设定项:

export function beforeWebStart() {
  var customScript = document.createElement('script');
  customScript.setAttribute('src', 'beforeStartScripts.js');
  document.head.appendChild(customScript);
}

export function afterWebStarted() {
  var customScript = document.createElement('script');
  customScript.setAttribute('src', 'afterStartedScripts.js');
  document.head.appendChild(customScript);
}

前面的 beforeWebStart 示例仅保证自定义脚本在 Blazor 启动之前加载。 它不保证脚本中等待的承诺在 Blazor 启动之前完成执行。

对于 Blazor Server、Blazor WebAssembly 和 Blazor Hybrid 应用:

下面的示例展示了通过将脚本追加到 JS 和 Blazor 中的 <head>,在 beforeStart 启动之前和之后加载自定义脚本的 afterStarted 初始值设定项:

export function beforeStart(options, extensions) {
  var customScript = document.createElement('script');
  customScript.setAttribute('src', 'beforeStartScripts.js');
  document.head.appendChild(customScript);
}

export function afterStarted(blazor) {
  var customScript = document.createElement('script');
  customScript.setAttribute('src', 'afterStartedScripts.js');
  document.head.appendChild(customScript);
}

前面的 beforeStart 示例仅保证自定义脚本在 Blazor 启动之前加载。 它不保证脚本中等待的承诺在 Blazor 启动之前完成执行。

注意

MVC 和 Razor 页面应用程序不会自动加载 JS 初始化程序。 但是,开发人员代码可以包含一个脚本,用于提取应用的清单并触发 JS 初始值设定项的加载。

有关 JS 初始化表达式的示例,请参阅以下资源:

注意

指向 .NET 参考源的文档链接通常会加载存储库的默认分支,该分支表示针对下一个 .NET 版本的当前开发。 若要为特定版本选择标记,请使用“切换分支或标记”下拉列表。 有关详细信息,请参阅如何选择 ASP.NET Core 源代码的版本标记 (dotnet/AspNetCore.Docs #26205)

确保按特定顺序加载库

按照应加载的顺序将自定义脚本追加到 <head>beforeStart 中的 afterStarted

以下示例在 script1.js 之前加载 script2.js,在 script3.js 之前加载 script4.js

export function beforeStart(options, extensions) {
    var customScript1 = document.createElement('script');
    customScript1.setAttribute('src', 'script1.js');
    document.head.appendChild(customScript1);

    var customScript2 = document.createElement('script');
    customScript2.setAttribute('src', 'script2.js');
    document.head.appendChild(customScript2);
}

export function afterStarted(blazor) {
    var customScript1 = document.createElement('script');
    customScript1.setAttribute('src', 'script3.js');
    document.head.appendChild(customScript1);

    var customScript2 = document.createElement('script');
    customScript2.setAttribute('src', 'script4.js');
    document.head.appendChild(customScript2);
}

导入其他模块

使用 import 初始值设定项文件中的顶级 JS 语句导入其他模块。

additionalModule.js:

export function logMessage() {
  console.log('logMessage is logging');
}

在 JS 初始值设定项文件 (.lib.module.js) 中:

import { logMessage } from "/additionalModule.js";

export function beforeStart(options, extensions) {
  ...

  logMessage();
}

导入映射

ASP.NET Core 和 支持Blazor。

文档准备就绪时初始化 Blazor

当文档准备就绪时,以下示例将启动 Blazor:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  document.addEventListener("DOMContentLoaded", function() {
    Blazor.start();
  });
</script>

在前面的示例中,{BLAZOR SCRIPT} 占位符是 Blazor 脚本路径和文件名。 有关脚本的位置,请参阅 ASP.NET Core Blazor 项目结构

链接到由手动启动生成的 Promise

若要执行其他任务(如 JS 互操作初始化),请使用 then 链接到 Promise(由手动 Blazor 应用启动生成):

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start().then(function () {
    ...
  });
</script>

在前面的示例中,{BLAZOR SCRIPT} 占位符是 Blazor 脚本路径和文件名。 有关脚本的位置,请参阅 ASP.NET Core Blazor 项目结构

注意

若要在 Blazor 启动后使库自动执行其他任务,请使用 JavaScript 初始值设定项。 使用 JS 初始值设定项不需要库的使用者将 JS 调用链接到 Blazor 的手动启动。

加载客户端启动资源

当应用程序在浏览器中加载时,该应用程序将从服务器下载启动资源:

  • 用于启动应用程序的 JavaScript 代码
  • .NET 运行时和程序集
  • 本地化数据

自定义如何使用 loadBootResource API 加载这些启动资源。 loadBootResource 函数会重写内置启动资源加载机制。 在以下场景中使用 loadBootResource

  • 从 CDN 加载静态资源,例如时区数据或 dotnet.wasm
  • 使用 HTTP 请求加载压缩的程序集,并将其解压缩到不支持从服务器提取压缩内容的主机的客户端上。
  • 将每个 fetch 请求重定向到新名称,从而为资源提供别名。

注意

外部源必须返回浏览器所需的跨源资源共享 (CORS) 标头以允许跨源资源加载。 CDN 通常会提供所需的标头。

loadBootResource 参数如下表所示。

参数 描述
type 资源类型。 允许的类型包括:assemblypdbdotnetjsdotnetwasmtimezonedata。 你只需指定自定义行为的类型。 框架会根据默认的加载行为加载未指定到 loadBootResource 的类型。 dotnetjs 启动资源 (dotnet.*.js) 必须返回表示默认加载行为的 null 或表示 dotnetjs 启动资源的源的 URI。
name 资源的名称。
defaultUri 资源的相对或绝对 URI。
integrity 表示响应中的预期内容的完整性字符串。

loadBootResource 函数可以返回 URI 字符串以替代加载进程。 在以下示例中,来自 bin/Release/{TARGET FRAMEWORK}/wwwroot/_framework 的以下文件从 CDN 的 https://cdn.example.com/blazorwebassembly/{VERSION}/ 提供:

  • dotnet.*.js
  • dotnet.wasm
  • 时区数据

{TARGET FRAMEWORK} 占位符是目标框架名字对象(例如 net7.0)。 {VERSION} 占位符是共享框架版本(例如 7.0.0)。

Blazor Web App:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    webAssembly: {
      loadBootResource: function (type, name, defaultUri, integrity) {
        console.log(`Loading: '${type}', '${name}', '${defaultUri}', '${integrity}'`);
        switch (type) {
          case 'dotnetjs':
          case 'dotnetwasm':
          case 'timezonedata':
            return `https://cdn.example.com/blazorwebassembly/{VERSION}/${name}`;
        }
      }
    }
  });
</script>

在前面的示例中,{BLAZOR SCRIPT} 占位符是 Blazor 脚本路径和文件名。 有关脚本的位置,请参阅 ASP.NET Core Blazor 项目结构

独立 Blazor WebAssembly:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    loadBootResource: function (type, name, defaultUri, integrity) {
      console.log(`Loading: '${type}', '${name}', '${defaultUri}', '${integrity}'`);
      switch (type) {
        case 'dotnetjs':
        case 'dotnetwasm':
        case 'timezonedata':
          return `https://cdn.example.com/blazorwebassembly/{VERSION}/${name}`;
      }
    }
  });
</script>

在前面的示例中,{BLAZOR SCRIPT} 占位符是 Blazor 脚本路径和文件名。 有关脚本的位置,请参阅 ASP.NET Core Blazor 项目结构

除了为启动资源自定义 URL 外,该 loadBootResource 函数还可以直接调用 fetch 并返回结果。 以下示例将一个自定义 HTTP 标头添加到出站请求。 若要保持默认的完整性检查行为,请传递 integrity 参数。

Blazor Web App:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    webAssembly: {
      loadBootResource: function (type, name, defaultUri, integrity) {
        if (type == 'dotnetjs') {
          return null;
        } else {
          return fetch(defaultUri, {
            cache: 'no-cache',
            integrity: integrity,
            headers: { 'Custom-Header': 'Custom Value' }
          });
        }
      }
    }
  });
</script>

在前面的示例中,{BLAZOR SCRIPT} 占位符是 Blazor 脚本路径和文件名。 有关脚本的位置,请参阅 ASP.NET Core Blazor 项目结构

独立 Blazor WebAssembly:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    loadBootResource: function (type, name, defaultUri, integrity) {
      if (type == 'dotnetjs') {
        return null;
      } else {
        return fetch(defaultUri, {
          cache: 'no-cache',
          integrity: integrity,
          headers: { 'Custom-Header': 'Custom Value' }
        });
      }
    }
  });
</script>

在前面的示例中,{BLAZOR SCRIPT} 占位符是 Blazor 脚本路径和文件名。 有关脚本的位置,请参阅 ASP.NET Core Blazor 项目结构

loadBootResource 函数返回 null 时,Blazor 采用资源的默认加载行为。 例如,上述代码为 null 启动资源 (dotnetjs) 返回 dotnet.*.js,因为 dotnetjs 启动资源必须返回表示默认加载行为的 null 或表示 dotnetjs 启动资源的源的 URI。

loadBootResource 函数还可以返回 Response promise。 有关示例,请参阅托管和部署 ASP.NET Core Blazor WebAssembly

有关详细信息,请参阅 ASP.NET 核心 Blazor WebAssembly 缓存和完整性检查失败

控制 C# 代码中的标头

使用下列方法控制 C# 代码中启动时的标头。

在以下示例中,通过 CSP 标头将内容安全策略 (CSP) 应用于应用。 {POLICY STRING} 占位符是 CSP 策略字符串。 有关 CSP 的详细信息,请参阅为 ASP.NET Core Blazor 强制实施内容安全策略

注意

响应启动后,无法设置标头。 本部分中的方法仅在响应启动前设置标头,因此此处介绍的方法是安全的。 有关详细信息,请参阅ASP.NET Core Blazor 应用中的 IHttpContextAccessor/HttpContext

服务器端和预呈现的客户端情景

使用 ASP.NET Core 中间件来控制标头集合。

Program 文件中:

Startup.ConfigureStartup.cs 中:

app.Use(async (context, next) =>
{
    context.Response.Headers.Append("Content-Security-Policy", "{POLICY STRING}");
    await next();
});

前面的示例使用内联中间件,但你也可以创建自定义中间件类,并使用 Program 文件中的扩展方法调用中间件。 有关详细信息,请参阅编写自定义 ASP.NET Core 中间件

无需预呈现的客户端开发

StaticFileOptions 传递给 MapFallbackToFile,以指定 OnPrepareResponse 阶段的响应标头。

在服务器端 Program 文件中:

Startup.ConfigureStartup.cs 中:

var staticFileOptions = new StaticFileOptions
{
    OnPrepareResponse = context =>
    {
        context.Context.Response.Headers.Append("Content-Security-Policy", 
            "{POLICY STRING}");
    }
};

...

app.MapFallbackToFile("index.html", staticFileOptions);

客户端端加载指示器

加载指示器显示应用正在正常加载,并且用户应等待加载完成。

Blazor Web App 加载指示器

应用中使用的 Blazor WebAssembly 加载指示器不在从 Blazor Web App 项目模板创建的应用中。 通常,加载指示器并不适合交互式 WebAssembly 组件,因为 Blazor Web App 在服务器上预渲染客户端组件,可以实现快速的初始加载时间。 对于混合呈现模式的情况,框架或开发人员代码还必须注意避免以下问题:

  • 在同一呈现页面上显示多个加载指示器。
  • 在加载 .NET WebAssembly 运行时时无意中丢弃了预呈现的内容。

.NET 的未来版本可能提供基于框架的加载指示器。 与此同时,您可以将自定义加载指示器添加到Blazor Web App。

具有预呈现的每个分量交互式 WebAssembly 呈现

此方案适用于逐个组件的交互式 WebAssembly 渲染(@rendermode InteractiveWebAssembly 应用于单个组件)。

ContentLoading应用的Layout文件夹中创建.Client组件,该组件调用OperatingSystem.IsBrowser

  • false 时,显示加载指示器。
  • true 时,呈现请求的组件的内容。

要为指示器加载 CSS 样式,请将样式添加到附带 <head> 组件的 HeadContent 内容中。 有关详细信息,请参阅在 ASP.NET Core Blazor 应用中控制页面头部内容

Layout/ContentLoading.razor:

@if (!RendererInfo.IsInteractive)
{
    <!-- OPTIONAL ...
    <HeadContent>
        <style>
            ...
        </style>
    </HeadContent>
    -->
    <progress id="loadingIndicator" aria-label="Content loading…"></progress>
}
else
{
    @ChildContent
}

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}
@if (!OperatingSystem.IsBrowser())
{
    <!-- OPTIONAL ...
    <HeadContent>
        <style>
            ...
        </style>
    </HeadContent>
    -->
    <progress id="loadingIndicator" aria-label="Content loading…"></progress>
}
else
{
    @ChildContent
}

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}

如果项目中还没有 Layout 文件夹 .Client ,请将文件夹的 Layout 命名空间添加到 _Imports.razor 文件中。 在以下示例中,项目的命名空间为 BlazorSample.Client

@using BlazorSample.Client.Layout

在采用交互式 WebAssembly 呈现的组件中,使用 Razor 组件包装组件的 ContentLoading 标记。 下面的示例使用从 Counter 项目模板创建应用的 Blazor Web App 组件演示了该方法。

Pages/Counter.razor:

@page "/counter"
@rendermode InteractiveWebAssembly

<PageTitle>Counter</PageTitle>

<ContentLoading>
    <h1>Counter</h1>

    <p role="status">Current count: @currentCount</p>

    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</ContentLoading>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

具有预呈现的全局交互式 WebAssembly 呈现

此方案适用于具有预呈现的全局交互式 WebAssembly 呈现(在 @rendermode="InteractiveWebAssembly" 分量的 HeadOutletRoutes 分量上的 App)。

ContentLoading应用的Layout文件夹中创建.Client组件,该组件调用RendererInfo.IsInteractive

  • false 时,显示加载指示器。
  • true 时,呈现请求的组件的内容。

要为指示器加载 CSS 样式,请将样式添加到附带 <head> 组件的 HeadContent 内容中。 有关详细信息,请参阅在 ASP.NET Core Blazor 应用中控制页面头部内容

Layout/ContentLoading.razor:

@if (!RendererInfo.IsInteractive)
{
    <!-- OPTIONAL ...
    <HeadContent>
        <style>
            ...
        </style>
    </HeadContent>
    -->
    <progress id="loadingIndicator" aria-label="Content loading…"></progress>
}
else
{
    @ChildContent
}

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}
@if (!OperatingSystem.IsBrowser())
{
    <!-- OPTIONAL ...
    <HeadContent>
        <style>
            ...
        </style>
    </HeadContent>
    -->
    <progress id="loadingIndicator" aria-label="Content loading…"></progress>
}
else
{
    @ChildContent
}

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}

如果项目中还没有 Layout 文件夹 .Client ,请将文件夹的 Layout 命名空间添加到 _Imports.razor 文件中。 在以下示例中,项目的命名空间为 BlazorSample.Client

@using BlazorSample.Client.Layout

MainLayout项目的Layout/MainLayout.razor组件(.Client)中,用Body组件包装@Body属性(ContentLoading):

Layout/MainLayout.razor中:

+ <ContentLoading>
    @Body
+ </ContentLoading>

不具有预呈现的全局交互式 WebAssembly 呈现

此方案适用于不具有预呈现的全局交互式 WebAssembly 呈现(在 @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" 分量的 HeadOutletRoutes 分量上的 App)。

JavaScript 初始值设定项 添加到应用。 在以下 JavaScript 模块文件名示例中, {ASSEMBLY NAME} 占位符是服务器项目的程序集名称(例如, BlazorSample)。 wwwroot模块所在的文件夹是wwwroot服务器端项目中的文件夹,而不是.Client项目。

以下示例使用一个 progress 指示器,它并不指示实际的进度,仅为将 客户端启动资源传送到客户端提供一个通用的开发方法。如果您想让进度指示器显示加载应用启动资源的实际进度,可以在此基础上进行进一步开发。

wwwroot/{ASSEMBLY NAME}.lib.module.js:

export function beforeWebStart(options) {
  var progress = document.createElement("progress");
  progress.id = 'loadingIndicator';
  progress.ariaLabel = 'Blazor loading…';
  progress.style = 'position:absolute;top:50%;left:50%;margin-right:-50%;' +
    'transform:translate(-50%,-50%);';
  document.body.appendChild(progress);
}

export function afterWebAssemblyStarted(blazor) {
  var progress = document.getElementById('loadingIndicator');
  progress.remove();
}

由于 .NET 8 和 9(dotnet/aspnetcore #54049)中的框架缺陷,必须手动启动 Blazor 脚本。 如果服务器应用尚未使用 WebAssembly (Blazor) 配置手动启动 webAssembly: {...},请在服务器项目中使用以下内容更新 App 组件。

Components/App.razor中,删除现有 Blazor<script> 标记:

- <script src="_framework/blazor.web.js"></script>

<script> 标记替换为以下标记,这些标记使用 WebAssembly (Blazor) 配置手动启动 webAssembly: {...}

<script src="_framework/blazor.web.js" autostart="false"></script>
<script>
    Blazor.start({
        webAssembly: {}
    });
</script>

如果注意到加载指示器被移除与第一页渲染之间有短暂的延迟,可以通过在 OnAfterRenderAsync 分量的 MainLayout中调用指示器移除来确保在呈现后删除指示器。 有关详细信息和代码示例,请参阅记录一种与不具有预呈现的全局交互式 WebAssembly 一起使用的加载指示器的方法 (dotnet/AspNetCore.Docs #35111)

Blazor WebAssembly 应用加载进度

项目模板包含可缩放矢量图形 (SVG) 和显示应用加载进度的文本指示器。

进度指示器是使用 Blazor 提供的两个 CSS 自定义属性(变量)通过 HTML 和 CSS 实现的:

  • --blazor-load-percentage:加载的应用文件的百分比。
  • --blazor-load-percentage-text:加载的应用文件的百分比,四舍五入为最接近的整数。

使用上述 CSS 变量可以创建与应用样式匹配的自定义进度指示器。

在下面的示例中:

  • resourcesLoaded 是应用启动期间加载的资源的瞬时计数。
  • totalResources 是要加载的资源总数。
const percentage = resourcesLoaded / totalResources * 100;
document.documentElement.style.setProperty(
  '--blazor-load-percentage', `${percentage}%`);
document.documentElement.style.setProperty(
  '--blazor-load-percentage-text', `"${Math.floor(percentage)}%"`);

默认舍入进度指示器在 wwwroot/index.html 文件中的 HTML 中实现:

<div id="app">
    <svg class="loading-progress">
        <circle r="40%" cx="50%" cy="50%" />
        <circle r="40%" cx="50%" cy="50%" />
    </svg>
    <div class="loading-progress-text"></div>
</div>

若要查看默认进度指示器的 项目模板标记和样式,请参阅 ASP.NET Core 参考源:

注意

指向 .NET 参考源的文档链接通常会加载存储库的默认分支,该分支表示针对下一个 .NET 版本的当前开发。 若要为特定版本选择标记,请使用“切换分支或标记”下拉列表。 有关详细信息,请参阅如何选择 ASP.NET Core 源代码的版本标记 (dotnet/AspNetCore.Docs #26205)

以下示例演示了如何实现线性进度指示器,而不是使用默认的舍入进度指示器。

wwwroot/css/app.css 添加以下样式:

.linear-progress {
    background: silver;
    width: 50vw;
    margin: 20% auto;
    height: 1rem;
    border-radius: 10rem;
    overflow: hidden;
    position: relative;
}

.linear-progress:after {
    content: '';
    position: absolute;
    inset: 0;
    background: blue;
    scale: var(--blazor-load-percentage, 0%) 100%;
    transform-origin: left top;
    transition: scale ease-out 0.5s;
}

CSS 变量 (var(...)) 用于将 --blazor-load-percentage 的值传递给蓝色伪元素的 scale 属性,该属性指示应用文件的加载进度。 当应用加载时,--blazor-load-percentage 会自动更新,这会动态更改进度指示器的可视表示形式。

wwwroot/index.html 中,删除 <div id="app">...</div> 中的默认 SVG 舍入指示器,并将其替换为以下标记:

<div class="linear-progress"></div>

配置 .NET WebAssembly 运行时

在高级编程方案中,会将 configureRuntime 函数与 dotnet 运行时主机生成器配合使用来配置 .NET WebAssembly 运行时。 例如,dotnet.withEnvironmentVariable 设置一个环境变量:

  • 配置 .NET WebAssembly 运行时。
  • 更改 C 库的行为。

注意

dotnet/runtime GitHub 存储库中有一个文档请求正在等待处理,以获取有关配置 .NET WebAssembly 运行时或影响 C 库行为的环境变量的详细信息。 尽管文档请求处于挂起状态,但请求中提供了指向其他资源的详细信息和交叉链接有关 .NET WASM 运行时环境变量的文档的问题/请求 (dotnet/runtime #98225)

configureRuntime 函数还可用于启用与浏览器探查器的集成

对于以下示例中用于设置环境变量的占位符:

  • {BLAZOR SCRIPT} 占位符是 Blazor 脚本路径和文件名。 有关脚本的位置,请参阅 ASP.NET Core Blazor 项目结构
  • {NAME} 占位符是环境变量的名称。
  • {VALUE} 占位符是环境变量的值。

Blazor Web App:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    webAssembly: {
      configureRuntime: dotnet => {
        dotnet.withEnvironmentVariable("{NAME}", "{VALUE}");
      }
    }
  });
</script>

在前面的示例中,{BLAZOR SCRIPT} 占位符是 Blazor 脚本路径和文件名。 有关脚本的位置,请参阅 ASP.NET Core Blazor 项目结构

独立 Blazor WebAssembly:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    configureRuntime: dotnet => {
      dotnet.withEnvironmentVariable("{NAME}", "{VALUE}");
    }
  });
</script>

在前面的示例中,{BLAZOR SCRIPT} 占位符是 Blazor 脚本路径和文件名。 有关脚本的位置,请参阅 ASP.NET Core Blazor 项目结构

注意

可使用 .NET WebAssembly 运行时 API (Blazor.runtime) 访问 .NET 运行时实例。 例如,可以使用 Blazor.runtime.runtimeBuildInfo.buildConfiguration 获取应用的生成配置。

有关 .NET WebAssembly 运行时配置的详细信息,请参阅 dotnet.d.ts GitHub 存储库中的运行时 TypeScript 定义文件 (dotnet/runtime)

注意

指向 .NET 参考源的文档链接通常会加载存储库的默认分支,该分支表示针对下一个 .NET 版本的当前开发。 若要为特定版本选择标记,请使用“切换分支或标记”下拉列表。 有关详细信息,请参阅如何选择 ASP.NET Core 源代码的版本标记 (dotnet/AspNetCore.Docs #26205)

禁用增强型导航和表单处理

本部分适用于 Blazor Web App。

若要禁用增强型导航和表单处理,请将 disableDomPreservationtrue 设置为 Blazor.start

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    ssr: { disableDomPreservation: true }
  });
</script>

在前面的示例中,{BLAZOR SCRIPT} 占位符是 Blazor 脚本路径和文件名。 有关脚本的位置,请参阅 ASP.NET Core Blazor 项目结构

其他资源