.NET 5 Release Candidate(RC1)版本现在可以进行使用了,以下是发布的新功能:

  • Blazor WebAssembly性能改进
  • Blazor组件虚拟化
  • Blazor WebAssembly预渲染
  • Blazor WebAssembly的浏览器兼容性分析器
  • Blazor JavaScript隔离和对象引用
  • Blazor文件输入支持
  • Blazor中的自定义验证类属性
  • Blazor对ontogle事件的支持
  • 模型绑定DateTime为UTC
  • 控制Startup类的激活
  • ASP.NET Core API项目中的默认开放式API规范(Swagger)
  • ASP.NET Core API项目提供更好的F5体验
  • SignalR并行集线器调用
  • 在SignalR Java客户端中添加了对Messagepack支持
  • Kestrel终端可进行特定的选项配置

Get started

如果要在.NET 5 RC1中使用ASP.NET Core我们需要安装.NET5 SDK。.NET RC1也包含了在Visual Studio 2019 16.8 Preview 3中。

我们需要使用Visual Studio 2019 16.8 Preview 3或者更高的版本才能使用.NET5 RC1。最新的Mac版Visual Studio预览版也支持.NET5。要将.NET 5与Visual Studio Code一起使用,请安装最新版本的C#扩展

Upgrade an existing project

ASP.NET Core应用从.NET5 preview8升级到.NET5 RC1,可以通过如下步骤来升级:

  • 将所有Microsoft.AspNetCore.包引用更新为5.0.0-rc.1.
    • 如果使用的是新的Microsoft.AspNetCore.Components.Web.Extensions程序包,需要更新版本到5.0.0-preview.9.*。目前这个包还有RC版本,因为开发团队希望在准备发布之前对它包含的组件进行更多的设计和更改。
  • 将所有Microsoft.Extensions.程序包引用更新为5.0.0-rc.1.
  • 将System.Net.Http.Json包引用更新为5.0.0-rc.1.*

在Blazor WebAssembly项目中,还可以对项目文件进行如下的更新:

  • 将SDK从Microsoft.NET.Sdk.Web修改为Microsoft.NET.Sdk.BlazorWebAssembly
  • 删除 <RuntimeIdentifier>browser-wasm</RuntimeIdentifier><UseBlazorWebAssembly>true</UseBlazorWebAssembly> 属性

What’s new?

Blazor WebAssembly performance improvements

对于.NET5开发团队已经对Blazor WebAssembly运行时性能进行了重大的改进,特别是对于复杂的UI和JSON序列化,在开发团队的性能测试中,据了解在大多数情况下,Blazor WebAssembly在.NET5中速度要快2-3倍。

.NET5中的Blazor WebAssembly中的运行时代码执行通常比Blazor WebAssembly3.2快,这是由于核心框架的优化和.NET IL解释器的改进,在.NET5 WebAssembly中,如字符串比较,字典查找和JSON处理之类的操作通常要快很多。

如下图所示,在.NET5中WebAssembly JSON的处理几乎快了一倍:

image

开发团队还优化了Blazor组件渲染的性能,尤其是对于涉及大量组件的UI,例如使用高密度grids时。

为了测试.NET5中grid组件呈现的性能,开发团队使用了三种不同的grid组件实现,每个实现呈现200行和20列:

  • Fast Grid: 一个最小的,高度优化grid实现
  • Plain Table: 一个最小的,但是没有优化的grid实现
  • Complex Grid: 一个最大的,没有优化的grid实现,故意应用大量的Blazor特性,故意对渲染器造成不良影响。

从测试来看grid渲染在.NET5中grid的渲染速度快了2-3倍

image

我们可以在GitHub中找到这些性能测试的代码

我们可以期待正在进行的工作来改善Blazor WebAssembly的性能。.NET团队除了优化Blazor WebAssembly运行时和框架之外,还与浏览器实现者合作,以进一步加快WebAssembly的执行速度。对于.NET6开发团队打算向WebAssembly提供对提前编译(AoT)的支持,这将进一步提高性能。

Blazor component virtualization

我们可以使用新的内置虚拟化支持进一步提高组件呈现的性能。虚拟化是一种将UI呈现限制为当前可见的部分的技术,例如,当我们有一个包含许多行的长列表或表,但在任何给定时间只有一个小子集可见时。.NET 5中的Blazor添加了一个新的虚拟化组件,可以轻松地将虚拟化添加到组件中。

典型的基于列表或表的组件可能使用c# foreach循环来呈现列表中的每一项或表中的每一行,就像这样:

@foreach (var employee in employees)
{
    <tr>
        <td>@employee.FirstName</td>
        <td>@employee.LastName</td>
        <td>@employee.JobTitle</td>
    </tr>
}

如果列表增加到包含数千行,那么呈现它的可能需要一段时间,从而导致UI明显的延迟行为。

相反我们可以用Virtualize组件替换foreach循环,该组件仅呈现当前可见的行。

<Virtualize Items="employees" Context="employee">
    <tr>
        <td>@employee.FirstName</td>
        <td>@employee.LastName</td>
        <td>@employee.JobTitle</td>
    </tr>
</Virtualize>

Virtualize组件根据容器的高度和已渲染项目的大小来计算要渲染的items数量。

如果您不想将所有items都加载到内存中,则可以指定一个ItemsProvider,如下所示:

<Virtualize ItemsProvider="LoadEmployees" Context="employee">
     <tr>
        <td>@employee.FirstName</td>
        <td>@employee.LastName</td>
        <td>@employee.JobTitle</td>
    </tr>
</Virtualize>

items提供者是一种委托方法,可以按需异步检索请求的items。 Items提供程序会收到ItemsProviderRequest,该请求指定从特定起始索引开始的所需Items数量。 然后,项目提供程序从数据库或其他服务中检索请求的items,并将它们作为ItemsProviderResult <TItem>连同可用items总数一起返回。 items提供者可以选择在每个请求中检索items,或将其缓存以方便使用。

async ValueTask<ItemsProviderResult<Employee>> LoadEmployees(ItemsProviderRequest request)
{
    var numEmployees = Math.Min(request.Count, totalEmployees - request.StartIndex);
    var employees = await EmployeesService.GetEmployeesAsync(request.StartIndex, numEmployees, request.CancellationToken);
    return new ItemsProviderResult<Employee>(employees, totalEmployees);
}

因为从远程数据源请求items可能需要一些时间,所以我们还可以选择渲染占位符,知道items数据可用为止。

<Virtualize ItemsProvider="LoadEmployees" Context="employee">
    <ItemContent>
        <tr>
            <td>@employee.FirstName</td>
            <td>@employee.LastName</td>
            <td>@employee.JobTitle</td>
        </tr>
    </ItemContent>
    <Placeholder>
        <tr>
            <td>Loading...</td>
        </tr>
    </Placeholder>
</Virtualize>

Blazor WebAssembly prerendering

组件标签帮助器现在支持两种额外的渲染模式预先从Blazor WebAssembly应用程序中呈现组件:

  • WebAssemblyPrerendered: 将组件预渲染为静态HTML,并包含Blazor WebAssembly应用程序的标记,以便以后在加载到浏览器中时使组件具有交互性
  • WebAssembly: 渲染Blazor WebAssembly应用程序的标记,以便在加载到浏览器中时包含一个交互式组件。 该组件未呈现。 这个选项使在不同的cshtml页面上呈现不同的Blazor WebAssembly组件更加容易。

要在Blazor WebAssembly应用中设置预渲染,请执行以下操作:

1.将Blazor WebAssembly应用程序托管在ASP.NET Core应用程序中。

2.将客户端项目中的默认静态index.html文件替换为服务器项目中的*_Host.cshtml*文件。

3.更新服务器启动逻辑,以回退到*_Host.cshtml而不是index.html*(类似于Blazor Server模板的设置方式)。

4.更新*_Host.cshtml*以使用组件标签助手来预渲染根App组件:

<component type="typeof(App)" render-mode="WebAssemblyPrerendered" />

如果参数是可序列化的,则在使用基于WebAssembly的呈现方式时,还可以将参数传递给组件标签帮助器。 这些参数必须是可序列化的,以便可以将其传输到客户端并用于在浏览器中初始化组件。 如果要进行预渲染,则还需要确保编写了组件,以便它们可以在不访问浏览器的情况下优雅地执行服务器端。

<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" param-IncrementAmount="10" />

除了改善Blazor WebAssembly应用程序加载时间之外,我们还可以使用带有新渲染模式的component tag helper来在不同的页面和视图上添加多个组件,我们不需要将这些组件配置为应用程序的根组件,也不需要在页面上添加我们自己的标记,框架会为我们处理这些。

Browser compatibility analyzer for Blazor WebAssembly

Blazor WebAssembly应用在.NET5中的目标是完整的.NET5 API,但是由于浏览器沙箱的限制,WebAssembly上并不是支持所有的.NET5 API。.NET 5现在包含了一个平台兼容性分析器,当你的应用程序使用了你的目标平台不支持的api时,它会警告你。对于Blazor WebAssembly应用程序,这意味着检查浏览器是否支持api。

我们还没有将所有的注释添加到.NET 5的核心库中,现在已经注释了一些API(主要是Windows特定的API)

image

要启用浏览器对库的兼容性检查,请在项目文件中添加浏览器作为受支持的平台(Blazor WebAssembly项目和Razor类库项目为您完成这一任务)

<SupportedPlatform Include="browser" />

在创建库时,我们可以通过应用UnsupportedOSPlatformAttribute来选择性地指示浏览器中不支持某个特定的API

[UnsupportedOSPlatform("browser")]
private static string GetLoggingDirectory()
{
    // ...
}

Blazor JavaScript isolation and object references

Blazor现在可以将JavaScript隔离为标准的JavaScript模块。这有几个好处

1.导入的JavaScript不再污染全局名称空间。

2.库和组件的使用者不再需要手动导入相关的JavaScript。

例如,以下JavaScript模块导出一个简单的JavaScript函数以显示浏览器提示:

export function showPrompt(message) {
    return prompt(message, 'Type anything here');
}

我们可以将这个JavaScript模块作为一个静态网络资产(wwwroot/exampleJsInterop.js)添加到我们的.NET库中,然后使用IJSRuntime服务将该模块导入到.NET代码中。

var module = await jsRuntime.InvokeAsync<JSObjectReference>("import", "./_content/MyComponents/exampleJsInterop.js");

“import”标识符是专门用于导入JavaScript模块的特殊标识符。我们可以使用稳定的静态web资产路径指定模块 _content/[LIBRARY NAME]/[PATH UNDER WWWROOT].

IJSRuntime将该模块作为JSObjectReference导入,该对象代表.NET代码对JavaScript对象的引用。 然后,我们可以使用JSObjectReference从模块调用导出的JavaScript函数:

public async ValueTask<string> Prompt(string message)
{
    return await module.InvokeAsync<string>("showPrompt", message);
}

JSObjectReference极大地简化了与JavaScript库的交互,在这些库中,您希望捕获JavaScript对象引用,然后再从.NET调用它们的函数。

Blazor file input support

Blazor现在提供了一个InputFile组件,用于处理文件上载,或更一般地说,是用于将浏览器文件数据读取到.NET代码中。

InputFile组件呈现为一个文件类型的HTML输入。默认情况下,用户可以选择单个文件,或者如果您添加了多个属性,那么用户可以同时提供多个文件。当用户选择一个或多个文件时,InputFile组件触发一个OnChange事件,并传递一个InputFileChangeEventArgs,该InputFileChangeEventArgs提供对所选文件列表的访问以及关于每个文件的详细信息。

<InputFile OnChange="OnInputFileChange" multiple />

<div class="image-list">
    @foreach (var imageDataUrl in imageDataUrls)
    {
        <img loading="lazy" src="@imageDataUrl" />
    }
</div>

@code {
    IList<string> imageDataUrls = new List<string>();

    async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        var imageFiles = e.GetMultipleFiles();

        var format = "image/png";
        foreach (var imageFile in imageFiles)
        {
            var resizedImageFile = await imageFile.RequestImageFileAsync(format, 100, 100);
            var buffer = new byte[resizedImageFile.Size];
            await resizedImageFile.OpenReadStream().ReadAsync(buffer);
            var imageDataUrl = $"data:{format};base64,{Convert.ToBase64String(buffer)}";
            imageDataUrls.Add(imageDataUrl);
        }
    }
}

要从用户选择的文件中读取数据,可以对该文件调用OpenReadStream并从返回的流中读取数据。在Blazor WebAssembly应用程序中,数据会直接流到浏览器中的.NET代码中。在Blazor服务器应用程序中,当您从流中读取文件数据时,文件数据将流化为服务器上的.NET代码。如果您使用组件来接收图像文件,Blazor还提供了一个RequestImageFileAsync便利方法,用于在图像数据流到。net应用程序之前,在浏览器的JavaScript运行时内调整图像数据的大小。

Custom validation class attributes in Blazor

现在可以在Blazor中指定自定义验证类名。这在与CSS框架(如Bootstrap)集成时非常有用。

要指定自定义验证类名,请创建一个从FieldCssClassProvider派生的类,并在EditContext实例上设置它。

var editContext = new EditContext(model);
editContext.SetFieldCssClassProvider(new MyFieldClassProvider());

// ...

class MyFieldClassProvider : FieldCssClassProvider
{
    public override string GetFieldCssClass(EditContext editContext, in FieldIdentifier fieldIdentifier)
    {
        var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();
        return isValid ? "legit" : "totally-bogus";
    }
}

Blazor support for ontoggle event

Blazor现在支持ontoggle事件:

<div>
    @if (detailsExpanded)
    {
        <p>Read the details carefully!</p>
    }
    <details id="details-toggle" @ontoggle="OnToggle">
        <summary>Summary</summary>
        <p>Detailed content</p>
    </details>
</div>

@code {
    bool detailsExpanded;
    string message { get; set; }

    void OnToggle()
    {
        detailsExpanded = !detailsExpanded;
    }
}

Model binding DateTime as UTC

ASP.NET Core中的模型绑定现在支持将UTC时间字符串正确绑定到DateTime。 如果请求包含UTC时间字符串(例如https://example.com/mycontroller/myaction?time=2019-06-14T02%3A30%3A04.0576719Z),则模型绑定将正确地将其绑定到UTC DateTime而无需 需要进一步定制。

Control Startup class activation

提供了一个额外的UseStartup重载,它允许您提供一个工厂方法来控制启动类的激活。如果我们想要传递与主机一同初始化的其他启动参数,这将非常有用。

public class Program
{
    public static async Task Main(string[] args)
    {
        var logger = CreateLogger();
        var host = Host.CreateDefaultBuilder()
            .ConfigureWebHost(builder =>
            {
                builder.UseStartup(context => new Startup(logger));
            })
            .Build();

        await host.RunAsync();
    }
}

Open API Specification On-by-default

Open API规范是一种行业采用的约定,用于描述HTTP API并将它们集成到复杂的业务流程或与第三方进行集成。开放API得到了所有云提供商和许多API注册中心的广泛支持,因此从其Web API中发布开放API文档的开发人员有许多新的机会可以使用这些API。与开源项目Swashbuckle.AspNetCore维护人员合作。我们激动地宣布,我们很高兴地宣布,RC1中的ASP.NET Core API模板预先连接了对Swashbuckle的NuGet依赖关系,Swashbuckle是一种流行的开源NuGet包,可动态发出Open API文档。 Swashbuckle通过对您的API控制器进行自省并在运行时或在构建时使用Swashbuckle CLI生成Open API文档来做到这一点。

在.NET 5 RC1中,运行dotnet new webapi将导致默认启用开放API输出,但如果您希望禁用开放API,请使用dotnet new webapi——no-openapi true。所有为Web API项目创建的.csproj文件都将附带NuGet包引用。

<ItemGroup>
    <PackageReference Include="Swashbuckle.AspNetCore" Version="5.5.1" />
</ItemGroup>

除了.csproj文件中的NuGet包引用之外,我们还向Startup.cs中激活开放API文档生成的ConfigureServices方法添加了代码。

public void ConfigureServices(IServiceCollection services)
{

    services.AddControllers();
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApplication1", Version = "v1" });
    });
}

配置方法还预先连接到Swashbuckle中间件中。这将启动文档生成过程,并在开发模式下默认打开Swagger UI页面。这样,当我们发布到生产环境中时,开箱即用的体验就不会意外地暴露我们的API描述。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseSwagger();
        app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebApplication1 v1"));
    }

    // ...
}

Azure API Management Import

在ASP.NET Core API项目以这种方式连接到输出开放API, Visual Studio 2019版本16.8 Preview 2.1的发布体验将在发布流程中自动提供额外的步骤。使用Azure API管理的开发人员有机会在发布流期间自动将他们的API导入到Azure API管理中。

image

这一额外的发布步骤减少了HTTP API开发人员发布API并与Azure逻辑应用程序或PowerApps一起使用所需要执行的步骤。

Better F5 Experience for Web API Projects

通过默认启用开放API,我们能够显著改善Web API开发人员的F5体验。在.NET 5 RC1中,Web API模板是预先配置来加载Swagger UI页面的。Swagger UI页面不仅提供了我们为API添加的文档,还允许我们通过单击进行API测试。

image

SignalR parallel hub invocations

在.NET 5 RC1中,NET Core SignalR现在能够处理并行集线器调用。您可以更改默认行为,并允许客户端一次调用多个hub方法。

HubConnection hubConnection = HubConnectionBuilder.create("http://localhost:53353/MyHub")
        .withHubProtocol(new MessagePackHubProtocol())
        .build();

Added Messagepack support in SignalR Java client

我们推出了一个新的软件包,com.microsoft.signalr.messagepack,它将messagepack支持添加到SignalR java客户机。要使用messagepack集线器协议,请向连接构建器添加. withhubprotocol(new MessagePackHubProtocol())。

HubConnection hubConnection = HubConnectionBuilder.create("http://localhost:53353/MyHub")
        .withHubProtocol(new MessagePackHubProtocol())
        .build();

Kestrel endpoint-specific options via configuration

增加了对通过配置配置Kestrel的特定端点选项的支持。特定于终结点的配置包括所使用的Http协议、所使用的TLS协议、所选择的证书和客户机证书模式。

我们可以根据指定的服务器名称配置所选择的证书,作为客户机指示的TLS协议的服务器名称指示(SNI)扩展的一部分。Kestrel配置还支持主机名中的通配符前缀。

下面的示例向我们展示了如何使用配置文件指定特定于终结点的内容

{
  "Kestrel": {
    "Endpoints": {
      "EndpointName": {
        "Url": "https://*",
        "Sni": {
          "a.example.org": {
            "Protocols": "Http1AndHttp2",
            "SslProtocols": [ "Tls11", "Tls12"],
            "Certificate": {
              "Path": "testCert.pfx",
              "Password": "testPassword"
            },
            "ClientCertificateMode" : "NoCertificate"
          },
          "*.example.org": {
            "Certificate": {
              "Path": "testCert2.pfx",
              "Password": "testPassword"
            }
          },
          "*": {
            // At least one subproperty needs to exist per SNI section or it
            // cannot be discovered via IConfiguration
            "Protocols": "Http1",
          }
        }
      }
    }
  }
}

原文:https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-5-release-candidate-1/