ASP.NET Core 9.0 的新增功能

本文重点介绍 ASP.NET Core 9.0 中最重要的更改,并提供相关文档的链接。

本文已针对 .NET 9 预览版 5 进行了更新。

Blazor

本部分介绍 Blazor 的新功能。

.NET MAUIBlazor Hybrid 和 Web 应用解决方案模板

使用新的解决方案模板可以更轻松地创建共享相同 UI 的 .NET MAUI 本机应用和 Blazor Web 客户端应用。 本模板展示了如何创建客户端应用,以最大限度地重复使用代码,并针对 Android、iOS、Mac、Windows 和 Web。

此模板的主要功能包括:

  • 可为 Web 应用选择 Blazor 交互式呈现模式。
  • 自动创建相应的项目,包括 Blazor Web 应用(全局交互式自动渲染)和 .NET MAUIBlazor Hybrid 应用。
  • 创建的项目使用共享的 Razor 类库 (RCL) 来维护 UI 的 Razor 组件。
  • 附带的示例代码演示了如何使用依赖项注入为 Blazor Hybrid 应用和 Blazor Web 应用提供不同的接口实现。

若要开始,请安装 .NET 9 SDK 并安装包含模板的 .NET MAUI 工作负载:

dotnet workload install maui

在命令 shell 中使用以下命令从项目模板创建解决方案:

dotnet new maui-blazor-web

该模板也可以在 Visual Studio 中使用。

注意

目前,如果在每个页面/组件级别定义了 Blazor 渲染模式,会出现异常。 有关详细信息,请参阅 BlazorWebView 需要一种方法来启用 ResolveComponentForRenderMode 的重写 (dotnet/aspnetcore #51235)

有关详细信息,请参阅生成具有 Blazor Web 应用的 .NET MAUIBlazor Hybrid 应用

静态资产传递优化

MapStaticAssets 是一个新的中间件,可帮助优化任何 ASP.NET Core 应用(包括 Blazor 应用)中静态资产的传递。

有关详细信息,请参阅以下任一资源:

在运行时检测呈现位置、交互性和分配的呈现模式

我们引入了一个新的 API,旨在简化在运行时查询组件状态的过程。 此 API 提供以下功能:

  • 确定组件当前的执行位置:这对调试和优化组件性能特别有用
  • 检查组件是否在交互式环境中运行:这对于根据环境的交互性而有不同行为的组件很有帮助。
  • 检索为组件指定的渲染模式:了解渲染模式有助于优化渲染过程并提高组件的整体性能

改善了服务器端重新连接体验:

默认的服务器端重新连接体验进行了以下增强:

  • 当用户导航回线路已断开连接的应用时,将立即尝试重新连接,而不是等待下一次重新连接间隔的持续时间。 这可改善在浏览器选项卡中导航到已进入睡眠状态的应用时的用户体验。

  • 当重新连接尝试到达服务器,但服务器已释放线路时,页面会自动刷新。 这样可以防止用户在页面很可能成功重新连接的情况下,还需要手动刷新页面。

  • 重新连接计时使用计算的回退策略。 默认情况下,在尝试之间引入计算延迟之前,前几次重新连接尝试会快速连续进行,不会出现重试间隔。 可以指定一个函数来计算重试间隔,从而自定义重试间隔行为,如以下指数退避示例所示:

    Blazor.start({
      circuit: {
        reconnectionOptions: {
          retryIntervalMilliseconds: (previousAttempts, maxRetries) => 
            previousAttempts >= maxRetries ? null : previousAttempts * 1000
        },
      },
    });
    
  • 默认重新连接 UI 的样式已经过现代化设计。

有关详细信息,请参阅 ASP.NET Core BlazorSignalR 指南

简化 Blazor Web 应用的身份验证状态序列化

通过新的 API,可以更轻松地向现有 Blazor Web 应用添加身份验证。 创建使用个人帐户进行身份验证的新 Blazor Web 应用并启用基于 WebAssembly 的交互性时,该项目会在服务器和客户端项目中包括一个自定义 AuthenticationStateProvider

这些提供程序将用户的身份验证状态传输到浏览器。 在服务器上而不是在客户端上进行身份验证,可以让应用在预呈现期间和初始化 Blazor WebAssembly 运行时之前访问身份验证状态。

自定义 AuthenticationStateProvider 实现使用 永久性组件状态服务(PersistentComponentState)将身份验证状态序列化为 HTML 注释,然后重新从 WebAssembly 读取,以创建新的 AuthenticationState 实例。

如果通过 Blazor Web 应用项目模板开始,并选择“个人帐户”选项,那么这将非常适用,但如果尝试向现有项目添加身份验证,那么需要自己实现或复制大量代码。 现在可通过在服务器和客户端项目中调用 API(现在是 Blazor Web 应用项目模板的一部分)来添加此功能:

  • AddAuthenticationStateSerialization:添加必要的服务,以便在服务器上序列化身份验证状态。
  • AddAuthenticationStateDeserialization:添加必要的服务,以便在浏览器中反序列化身份验证状态。

默认情况下,API 只会序列化服务器端的名称和角色声明,以便在浏览器中访问。 可以将选项传递给 AddAuthenticationStateSerialization 以包括所有声明。

有关详细信息,请参阅 ** 文章的以下各部分:

将静态服务器端渲染 (SSR) 页面添加到全局交互式 Blazor Web 应用程序

随着 .NET 9 的发布,现在可以更简单地将静态 SSR 页面添加到采用全局交互性的应用程序中。

仅当应用程序具有无法使用交互式服务器或 WebAssembly 渲染的特定页面时,此方法才有用。 例如,对于依赖于读/写 HTTP cookie 并且只能在请求/响应周期中运行而无法通过交互式渲染加载的页面,可采用这种方法。 对于使用交互式渲染的页面,不应强制它们使用静态 SSR 渲染,因为这一方法的效率较低且对最终用户的响应较差。

通过 @attributeRazor 指令,用新属性 [ExcludeFromInteractiveRouting] 标记任意 Razor 组件页面:

@attribute [ExcludeFromInteractiveRouting]

应用该属性将停止交互式路由并导航到不同的页面。 入站导航会强制执行全页重载,而不是通过交互式路由解析页面。 全页重载会迫使顶级根组件从服务器重新渲染,通常情况下,这一组件是 App 组件 (App.razor),重新渲染可以让应用切换到其他顶级渲染模式。

HttpContext.AcceptsInteractiveRouting 扩展方法允许组件检测是否已为当前页面应用 [ExcludeFromInteractiveRouting]

App 组件中,使用以下示例中的模式:

  • 默认情况下,缺少 [ExcludeFromInteractiveRouting] 注释的页面会默认使用配备通用交互功能的 InteractiveServer 渲染模式。 可以将 InteractiveServer 替换为 InteractiveWebAssemblyInteractiveAuto 以指定不同的默认全局渲染模式。
  • 使用 [ExcludeFromInteractiveRouting] 注释的页面采用静态 SSR(PageRenderMode 指定为 null)。
<!DOCTYPE html>
<html>
<head>
    ...
    <HeadOutlet @rendermode="@PageRenderMode" />
</head>
<body>
    <Routes @rendermode="@PageRenderMode" />
    ...
</body>
</html>

@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    private IComponentRenderMode? PageRenderMode
        => HttpContext.AcceptsInteractiveRouting() ? InteractiveServer : null;
}

使用 HttpContext.AcceptsInteractiveRouting 扩展方法的替代方法是使用 HttpContext.GetEndpoint()?.Metadata 手动读取终结点元数据。

有关此功能的详细信息,请参阅 ASP.NET CoreBlazor 渲染模式中的参考资料。

构造函数注入

Razor 组件支持构造函数注入。

在以下示例中,部分(代码隐藏)类使用主构造函数注入了 NavigationManager 服务:

public partial class ConstructorInjection(NavigationManager navigation)
{
    protected NavigationManager Navigation { get; } = navigation;
}

有关详细信息,请参阅 ASP.NET Core Blazor 依赖项注入

交互式服务器组件的 Websocket 压缩

默认情况下,交互式服务器组件会为 WebSocket 连接 启用压缩,并将frame-ancestors内容安全策略 (CSP) 指令设置为 'self',这会仅允许在启用压缩时或提供 WebSocket 上下文的配置时将应用嵌入为该应用提供服务的来源的 <iframe> 中。

可以通过将 ConfigureWebSocketOptions 设为 null 来禁用压缩,这可以减少应用受攻击的风险,但可能会导致性能降低:

.AddInteractiveServerRenderMode(o => o.ConfigureWebSocketOptions = null)

请考虑使用带有值 'none'(需要单引号)的更严格的 frame-ancestors CSP,它允许 WebSocket 压缩,但会阻止浏览器将应用嵌入任何 <iframe>

.AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = "'none'")

有关更多信息,请参见以下资源:

处理 Blazor 中的键盘组合事件

新的 KeyboardEventArgs.IsComposing 属性指示键盘事件是否是组合会话的一部分。 跟踪键盘事件的组合状态对于处理国际字符输入法至关重要。

QuickGrid 添加了 OverscanCount 参数

QuickGrid 组件现在公开了一个 OverscanCount 属性,该属性用于指定启用虚拟化时在可见区域之前和之后渲染的附加行数。

默认 OverscanCount 为 3。 以下示例将 OverscanCount 提升到 4:

<QuickGrid ItemsProvider="itemsProvider" Virtualize="true" OverscanCount="4">
    ...
</QuickGrid>

SignalR

本部分介绍 SignalR 的新功能。

SignalR 中心支持多态类型

中心方法现在可接受基类(而不是派生类)来实现多态方案。 需要注释基类型才能实现多形性

public class MyHub : Hub
{
    public void Method(JsonPerson person)
    {
        if (person is JsonPersonExtended)
        {
        }
        else if (person is JsonPersonExtended2)
        {
        }
        else
        {
        }
    }
}

[JsonPolymorphic]
[JsonDerivedType(typeof(JsonPersonExtended), nameof(JsonPersonExtended))]
[JsonDerivedType(typeof(JsonPersonExtended2), nameof(JsonPersonExtended2))]
private class JsonPerson
{
    public string Name { get; set; }
    public Person Child { get; set; }
    public Person Parent { get; set; }
}

private class JsonPersonExtended : JsonPerson
{
    public int Age { get; set; }
}

private class JsonPersonExtended2 : JsonPerson
{
    public string Location { get; set; }
}

最小 API

本部分介绍最小 API 的新功能。

TypedResults 添加了 InternalServerErrorInternalServerError<TValue>

TypedResults 类是一种有用的工具,用于从最小的 API 返回基于强类型的 HTTP 状态代码响应。 TypedResults 现在包括用于从终结点返回“500 内部服务器错误”响应的工厂方法和类型。 下面是返回 500 响应的示例:

var app = WebApplication.Create();

app.MapGet("/", () => TypedResults.InternalServerError("Something went wrong!"));

app.Run();

OpenAPI

针对 OpenAPI 文档生成的内置支持

OpenAPI 规范是描述 HTTP API 的标准。 开发人员可通过此标准定义可插入至客户端生成器、服务器生成器、测试工具、文档等项目的 API 的形式。 在 .NET 9 Preview 中,ASP.NET Core 提供了内置支持,用于使用 Microsoft.AspNetCore.OpenApi 包生成表示基于控制器或最小 API 的 OpenAPI 文档。

以下突出显示的代码调用了下面两项内容:

  • AddOpenApi,用于将所需的依赖项注册到应用程序的 DI 容器中。
  • MapOpenApi,用于在应用程序的路由中注册所需的 OpenAPI 端点。
var builder = WebApplication.CreateBuilder();

builder.Services.AddOpenApi();

var app = builder.Build();

app.MapOpenApi();

app.MapGet("/hello/{name}", (string name) => $"Hello {name}"!);

app.Run();

使用以下命令在项目中安装 Microsoft.AspNetCore.OpenApi 包:

dotnet add package Microsoft.AspNetCore.OpenApi --prerelease

运行应用程序并导航到 openapi/v1.json 以查看生成的 OpenAPI 文档:

OpenAPI 文档

还可以通过添加 Microsoft.Extensions.ApiDescription.Server 包,在构建时生成 OpenAPI 文档:

dotnet add package Microsoft.Extensions.ApiDescription.Server --prerelease

在应用的项目文件中,添加以下内容:

<PropertyGroup>
  <OpenApiDocumentsDirectory>$(MSBuildProjectDirectory)</OpenApiDocumentsDirectory>
  <OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
</PropertyGroup>

运行 dotnet build 并检查项目目录中生成的 JSON 文件。

在构建时生成 OpenAPI 文档

ASP.NET Core 的内置 OpenAPI 文档生成为各种自定义和选项提供支持。 它提供文档和操作转换器,并且能够管理同一个应用程序的多个 OpenAPI 文档。

要了解有关 ASP.NET Core 的新 OpenAPI 文档功能的更多信息,请参阅新的 Microsoft.AspNetCore.OpenApi 文档

身份验证和授权

本部分介绍身份验证和授权的新功能。

OIDC 和 OAuth 参数自定义

OAuth 和 OIDC 身份验证处理程序现在具有 AdditionalAuthorizationParameters 选项,以便更轻松地自定义通常作为重定向查询字符串的一部分的授权消息参数。 在 .NET 8 及更早版本中,这需要在自定义处理程序中使用自定义 OnRedirectToIdentityProvider 回调或重写 BuildChallengeUrl 方法。 下面是 .NET 8 代码的示例:

builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
    options.Events.OnRedirectToIdentityProvider = context =>
    {
        context.ProtocolMessage.SetParameter("prompt", "login");
        context.ProtocolMessage.SetParameter("audience", "https://api.example.com");
        return Task.CompletedTask;
    };
});

前面的示例现在可以简化为以下代码:

builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
    options.AdditionalAuthorizationParameters.Add("prompt", "login");
    options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});

配置 HTTP.sys 扩展身份验证标志

现在,可以使用 HTTP.sys AuthenticationManager 上的新 EnableKerberosCredentialCachingCaptureCredentials 属性来配置 HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHINGHTTP_AUTH_EX_FLAG_CAPTURE_CREDENTIAL HTTP.sys 标志,以优化 Windows 身份验证的处理方式。 例如:

webBuilder.UseHttpSys(options =>
{
    options.Authentication.Schemes = AuthenticationSchemes.Negotiate;
    options.Authentication.EnableKerberosCredentialCaching = true;
    options.Authentication.CaptureCredentials = true;
});

杂项

以下部分介绍了其他新功能。

HybridCache

HybridCache API 弥补了现有 IDistributedCacheIMemoryCache API 中的一些差距。 它还添加了新功能,例如:

  • “踩踏”保护可防止系统对同一作业执行多个并行获取操作。
  • 可配置的序列化。

HybridCache 旨在作为现有 IDistributedCacheIMemoryCache 的即插即用替代品,并且提供了一个简单的 API 以便添加新的缓存代码。 它为进程内和进程外缓存提供统一的 API。

要了解 HybridCache API 的简化方式,请将其与使用 IDistributedCache 的代码进行比较。 下面是使用 IDistributedCache 方法的示例:

public class SomeService(IDistributedCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        var key = $"someinfo:{name}:{id}"; // Unique key for this combination.
        var bytes = await cache.GetAsync(key, token); // Try to get from cache.
        SomeInformation info;
        if (bytes is null)
        {
            // Cache miss; get the data from the real source.
            info = await SomeExpensiveOperationAsync(name, id, token);

            // Serialize and cache it.
            bytes = SomeSerializer.Serialize(info);
            await cache.SetAsync(key, bytes, token);
        }
        else
        {
            // Cache hit; deserialize it.
            info = SomeSerializer.Deserialize<SomeInformation>(bytes);
        }
        return info;
    }

    // This is the work we're trying to cache.
    private async Task<SomeInformation> SomeExpensiveOperationAsync(string name, int id,
        CancellationToken token = default)
    { /* ... */ }
}

每次都要处理很多工作,包括序列化之类的操作。 在缓存缺失的情况下,最终可能会有多个并发线程,对于这些线程而言,其均会经历如下过程:出现缓存缺失,获取基础数据,对数据执行序列化,然后将数据发送至缓存。

为了使用 HybridCache 简化和改进此代码,我们首先需要添加新库 Microsoft.Extensions.Caching.Hybrid

<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" Version="9.0.0" />

注册 HybridCache 服务,操作与注册 IDistributedCache 实现一样:

services.AddHybridCache(); // Not shown: optional configuration API.

现在大多数缓存问题都可以转移到 HybridCache

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // Unique key for this combination.
            async cancel => await SomeExpensiveOperationAsync(name, id, cancel),
            token: token
        );
    }
}

我们通过依赖注入提供了 HybridCache 抽象类的具体实现,但其目的是让开发人员可以提供 API 的自定义实现。 HybridCache 实现处理与缓存相关的所有内容,包括并发操作处理。 这里的 cancel 标记代表所有并发调用方的联合取消——而不仅仅是我们所见的指定调用方的取消(即 token)。

可以使用 TState 模式进一步优化高吞吐量方案,以避免捕获的变量和每个实例回调产生一些开销:

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync(string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // unique key for this combination
            (name, id), // all of the state we need for the final call, if needed
            static async (state, token) =>
                await SomeExpensiveOperationAsync(state.name, state.id, token),
            token: token
        );
    }
}

HybridCache 使用已配置的 IDistributedCache 实现(如有)进行辅助进程外缓存,例如使用 Redis。 但即使没有 IDistributedCacheHybridCache 服务仍将提供进程内缓存和“踩踏”保护。

对象重用说明

在使用 IDistributedCache 的典型现有代码中,每次从缓存中检索对象都会导致反序列化。 此行为意味着每个并发调用方都获取一个单独的对象实例,该实例无法与其他实例交互。 这实现了线程安全性,因为并发修改同一对象实例没有风险。

将根据现有 IDistributedCache 代码调整对 HybridCache 的大量使用,因此 HybridCache 在默认情况下会保留此行为,以避免引入并发 bug。 但是,给定用例本质上在以下前提下是线程安全的:

  • 要缓存的类型不可变。
  • 代码未修改它们。

在这种情况下,请通过以下方式通知 HybridCache 可以安全地重用实例:

  • 将类型标记为 sealed。 C# 中的 sealed 关键字表示类无法被继承。
  • 对其应用 [ImmutableObject(true)] 属性。 [ImmutableObject(true)] 属性指示创建对象后无法更改该对象的状态。

通过重用实例,HybridCache 可以减少与每次调用反序列化相关的 CPU 和对象分配开销。 在缓存对象较大或被经常访问的情况下,这会提高性能。

其他 HybridCache 功能

IDistributedCache 类似,HybridCache 支持通过 RemoveKeyAsync 方法使用特定键完成删除。

HybridCache 还为 IDistributedCache 实现提供可选 API,以避免 byte[] 分配。 此功能由 Microsoft.Extensions.Caching.StackExchangeRedisMicrosoft.Extensions.Caching.SqlServer 包的预览版本实现。

会在注册服务过程中配置序列化,支持通过 WithSerializer.WithSerializerFactory 方法进行特定于类型的通用序列化程序(通过 AddHybridCache 调用链接)。 默认情况下,库在内部处理 stringbyte[],并对其他所有内容使用 System.Text.Json,但是你可以使用 protobuf、xml 或其他任何内容。

HybridCache 支持较旧的 .NET 运行时,最低支持 .NET Framework 4.7.2 和 .NET Standard 2.0。

有关 HybridCache 的详细信息,请参阅 ASP.NET Core 中的 HybridCache 库

开发人员异常页改进

当应用程序在开发过程中引发未处理的异常时,系统将显示 ASP.NET Core 开发人员异常页面。 开发人员异常页面提供有关异常和请求的详细信息。

预览版 3 将终结点元数据添加到开发人员异常页面。 ASP.NET Core 使用终结点元数据来控制端点行为,例如路由、响应缓存、速率限制、OpenAPI 生成等。 下图显示了开发人员异常页面的 Routing 部分中的新元数据信息:

开发者异常页上的新元数据信息

在测试开发人员异常页时,发现了少量的日常实用体验提升。 这些提升均由预览版 4 实现:

  • 更合理的文本换行。 长 cookie、查询字符串值和方法名称不再添加水平浏览器滚动条。
  • 采用现代设计,并应用了更大的文本。
  • 表格大小更加一致。

以下动画图像显示了新的开发人员异常页面:

新的开发人员异常页面

字典调试改进

字典和其他键值集合的调试显示具有改进的布局。 键显示在调试程序的键列中,而不是与值连接在一起。 下图显示了调试程序中字典的旧显示和新显示。

之前:

以前的调试器体验

之后:

新的调试器体验

ASP.NET Core 有许多键值集合。 这种改进的调试体验适用于:

  • HTTP 头
  • 查询字符串
  • 窗体
  • Cookies
  • 查看数据
  • 路由数据
  • 功能

修复 IIS 中应用程序回收期间的 503 错误

默认情况下,IIS 收到回收或关闭通知与 ANCM 通知托管服务器启动关闭之间现在有 1 秒的延迟。 延迟可通过 ANCM_shutdownDelay 环境变量或通过设置 shutdownDelay 处理程序设置进行配置。 这两个值均以毫秒为单位。 延迟主要是为了降低争用的可能性,其中:

  • IIS 尚未开始对发送至新应用的请求进行排队。
  • ANCM 开始拒绝进入旧应用的新请求。

速度较慢的计算机或 CPU 使用率较高的计算机可能需要调整此值,以减少出现 503 错误的可能性。

设置 shutdownDelay 的示例:

<aspNetCore processPath="dotnet" arguments="myapp.dll" stdoutLogEnabled="false" stdoutLogFile=".logsstdout">
  <handlerSettings>
    <!-- Milliseconds to delay shutdown by.
    this doesn't mean incoming requests will be delayed by this amount,
    but the old app instance will start shutting down after this timeout occurs -->
    <handlerSetting name="shutdownDelay" value="5000" />
  </handlerSettings>
</aspNetCore>

该修补程序位于以全局方式安装的 ANCM 模块中,此模块包含在托管捆绑包中。

优化静态 Web 资产传送

创建高性能 Web 应用涉及优化到浏览器的资产传送。 这涉及许多方面,例如:

MapStaticAssets 是一个新的中间件,可帮助优化应用中静态资产的传送。 它旨在处理所有 UI 框架,包括 Blazor、Razor、Pages 和 MVC。 它通常是一个 UseStaticFiles 的直接替代品。

MapStaticAssets 的运作方式是结合生成和发布时过程来收集应用中所有静态资源的信息。 然后,运行时库会利用此信息有效地向浏览器提供这些文件。

但是,MapStaticAssets 在大多数情况下可以替换 UseStaticFiles,它已针对为应用在生成和发布时了解的资产提供服务进行了优化。 如果应用服务来自其他位置(如磁盘或嵌入资源)的资产,则应使用 UseStaticFiles

MapStaticAssets 提供了以下 UseStaticFiles 没有的好处:

  • 为应用中的所有资产生成时间压缩:
    • 在开发期间 gzip,在发布期间 gzip + brotli
    • 所有资产都经过压缩,目标是将资产大小降到最低。
  • 基于内容的 ETags:每个资源的 Etags 都是内容的 SHA-256 哈希的 Base64 编码字符串。 这可确保浏览器仅在文件内容发生更改时重新下载文件。

下表显示了默认的 Razor Pages 模板中 CSS 和 JS 文件的原始大小和压缩大小:

文件 原始 压缩 % 缩减
bootstrap.min.css 163 17.5 89.26%
jquery.js 89.6 28 68.75%
bootstrap.min.js 78.5 20 74.52%
总计 331.1 65.5 80.20%

下表显示了使用 Fluent UI Blazor 组件库的原始大小和压缩大小:

文件 原始 压缩 % 缩减
fluent.js 384 73 80.99%
fluent.css 94 11 88.30%
总计 478 84 82.43%

总共 478 KB 未压缩到 84 KB 压缩。

下表显示了使用 MudBlazorBlazor 组件库的原始大小和压缩大小:

文件 原始 压缩 约简
MudBlazor.min.css 541 37.5 93.07%
MudBlazor.min.js 47.4 9.2 80.59%
总计 588.4 46.7 92.07%

使用 MapStaticAssets 时自动进行优化。 添加或更新库(例如使用新的 JavaScript 或 CSS)时,资产将作为生成的一部分进行优化。 优化对于可具有较低带宽或不可靠的连接的移动环境尤其有利。

在服务器上启用动态压缩与使用 MapStaticAssets

在服务器上,与动态压缩相比,MapStaticAssets 具有以下优势:

  • 更简单,因为没有特定于服务器的配置。
  • 性能更高,因为资产在生成时被压缩。
  • 允许开发人员在生成过程中花费额外的时间,以确保资产的大小达到最小。

请查看下表,它将 MudBlazor 压缩与 IIS 动态压缩和 MapStaticAssets 进行了比较:

IIS gzip MapStaticAssets MapStaticAssets Reduction
≅ 90 37.5 59%