.NET Core 3.0 Preview 6中对ASP.NET Core和Blazor的更新

咱们都知道在6月12日的时候微软发布了.NET Core 3.0的第6个预览版。针对.NET Core 3.0的发布咱们国内的微软MVP-汪宇杰还发布的官翻版的博文进行了详细的介绍。具体的能够关注“汪宇杰博客”公众号,或者个人“DotNetCore实战”公众号而后在历史文章里面进行查阅。而咱们这篇文章将会介绍本次更新中对ASP.NET Core和Blazor所作的更新。固然本文的大部份内容翻译自ASP.NET的首席项目经理Daniel Roth的介绍。javascript

注:英语能力好的能够直接到文章末尾查看英文连接进行阅读。
做者:依乐祝
本文连接:https://www.cnblogs.com/yilezhu/p/11031441.htmlhtml

如下是此预览版中的新增功能列表:java

  • 新Razor特性:@attribute,@code,@key,@namespace,@functions中的标记
  • Blazor指令属性
  • Blazor应用程序的身份验证和受权支持
  • Razor类库中的静态资产
  • Json.NET再也不在项目模板中引用
  • 证书和Kerberos身份验证
  • SignalR自动从新链接
  • 托管gRPC客户端
  • gRPC客户端工厂
  • gRPC拦截器

有关其余详细信息和已知问题,请参阅发行说明git

开始

要在.NET Core 3.0 Preview 6中开始使用ASP.NET Core,请安装.NET Core 3.0 Preview 6 SDKgithub

若是您在Windows上使用Visual Studio进行的话,则还须要安装Visual Studio 2019的最新预览web

对于最新的客户端Blazor模板,还能够从Visual Studio Marketplace 安装最新的Blazor扩展算法

升级现有项目

要将现有的ASP.NET Core应用程序升级到.NET Core 3.0 Preview 6,请按照ASP.NET Core文档中迁移步骤进行操做数据库

另请参阅ASP.NET Core 3.0 中的重大更改的完整列表。npm

要将现有的ASP.NET Core 3.0 Preview 5项目升级到Preview 6:json

  • 更新Microsoft.AspNetCore.*包引用到3.0.0-preview6.19307.2
  • 在Blazor应用程序中:
    • 重命名@functions@code
    • 更新Blazor特定属性和事件处理程序以使用新的指令属性语法(参见下文)
    • 删除任何关于app.UseBlazor<TStartup>()的调用,换成在app.UseRouting()调用以前调用app.UseClientSideBlazorFiles<TStartup>()的方式。还要在app.UseEndpoints()的调用中调用endpoints.MapFallbackToClientSideBlazor<TStartup>("index.html")

以前的调用方式

app.UseRouting();

app.UseEndpoints(endpoints =>
{
    endpoints.MapDefaultControllerRoute();
});

app.UseBlazor<Client.Startup>();

更新以后的调用方式

app.UseClientSideBlazorFiles<Client.Startup>();

app.UseRouting();

app.UseEndpoints(endpoints =>
{
    endpoints.MapDefaultControllerRoute();
    endpoints.MapFallbackToClientSideBlazor<Client.Startup>("index.html");
});

Razor的新特性

咱们(由于是ASP.NET的首席项目经理Daniel Roth写的博客,因此用第一人称)在此版本中添加了对如下新Razor语言功能的支持。

@attribute

新的@attribute指令将指定的属性添加到生成的类中。

@attribute [Authorize]

@code

.razor文件(在.cshtml文件中不支持)中使用了新的@code指令来指定要做为附加成员添加到生成的类中的代码块。它至关于@functions,但如今有了更好的名称。

@code {
    int currentCount = 0;

    void IncrementCount()
    {
        currentCount++;
    }
}

@key

.razor文件中使用了新的@key指令属性,以指定Blazor diffing算法可用于保留列表中的元素或组件的值(任何对象或惟一标识符)。

<div>
    @foreach (var flight in Flights)
    {
        <DetailsCard @key="flight" Flight="@flight" />
    }
</div>

要了解须要此功能的缘由,请想象一下不实用此功能来呈现包含航班详细信息的卡片列表的场景:

<div>
    @foreach (var flight in Flights)
    {
        <DetailsCard Flight="@flight" />
    }
</div>

若是将新航班添加到航班列表的中间,则现有的详细信息卡实例应保持不受影响,而且应在呈现的输出中插入一个新的详细信息卡。

要想象这个,若是Flights之前包含[F0, F1, F2],那么这是以前的状态:

  • DetailsCard0,Flight = F0
  • DetailsCard1,Flight = F1
  • DetailsCard2,Flight = F2

......若是咱们在索引1中插入一个新的项目fnew,这就是所指望的插入以后的状态:

  • DetailsCard0,Flight = F0
  • DetailsCardNew,Flight = FNew
  • DetailsCard1,Flight = F1
  • DetailsCard2,Flight = F2

可是,实际插入后的状态以下:

  • DetailsCard0,Flight = F0
  • DetailsCard1,Flight = FNew
  • DetailsCard2,Flight = F1
  • DetailsCardNew,Flight = F2

系统没法知道DetailsCard2或DetailsCard3应保留它们与旧航班实例的关联,所以它只会将它们与列表中与其位置匹配的航班从新关联。所以,DetailsCard1和DetailsCard2使用新数据彻底重建本身,这是浪费的,有时甚至会致使用户可见问题(例如,输入焦点意外丢失)。

经过使用@keydiffing算法添加键能够关联新旧元素或组件。

@namespace

在*_Imports.razor*文件中使用时,指定生成的类或名称空间前缀的名称空间。该@namespace指令如今适用于页面和视图(.cshtml)应用程序,但如今它也支持组件(.razor)。

@namespace MyNamespace

标记@functions和本地功能

在视图和页面(.cshtml文件)中,您如今能够在@functions块和本地函数中的方法内添加标记。

@{ GreetPerson(person); }

@functions {
    void GreetPerson(Person person)
    {
        <p>Hello, <em>@person.Name!</em></p>
    }
}

Blazor指令属性

Blazor使用各类属性来影响组件的编译方式(例如ref,bind,事件处理程序等)。随着时间的推移,这些属性已经有机地添加到Blazor并使用不一样的语法。在这个Blazor版本中,咱们已经标准化了指令属性的通用语法。这使得Blazor使用的Razor语法更加一致和可预测。它还为将来的可扩展性铺平了道路。

指令属性都遵循如下语法,其中括号中的值是可选的:

@directive(-suffix(:name))(="value")

一些有效的例子:

<!-- directive -->
<div @directive>...</div>
<div @directive="value"></div>

<!-- directive with key/value arg-->
<div @directive:key>...</div>
<div @directive:key="value"></div>

<!-- directive with suffix -->
<div @directive-suffix></div>
<div @directive-suffix="value"></div>

<!-- directive with suffix and key/value arg-->
<div @directive-suffix:key></div>
<div @directive-suffix:key="value"></div>

全部Blazor内置指令属性都已更新为使用此新语法,以下所述。

事件处理程序

在Blazor中指定事件处理程序如今使用新的指令属性语法而不是普通的HTML语法。语法相似于HTML语法,但如今具备前导@字符。这使得C#事件处理程序与JS事件处理程序不一样。

<button @onclick="@Clicked">Click me!</button>

为C#事件处理程序指定委托时,@属性值当前仍须要前缀,但咱们但愿在未来的更新中删除此要求。

在未来,咱们还但愿使用指令属性语法来支持事件处理程序的其余功能。例如,中止事件传播可能看起来像这样(还没有实现,但它让您了解如今由指令属性启用的方案):

<button @onclick="Clicked" @onclick:stopPropagation>Click me!</button>

捆绑

<input @bind="myValue">...</input>
<input @bind="myValue" @bind:format="mm/dd">...</input>
<MyButton @bind-Value="myValue">...</MyButton>

<div @key="id">...</div>

参考

<button @ref="myButton">...</button>

Blazor应用程序的身份验证和受权支持

Blazor如今内置了对处理身份验证和受权的支持。服务器端Blazor模板如今支持使用ASP.NET Core Identity,Azure AD和Azure AD B2C启用全部标准身份验证配置的选项。咱们尚未更新Blazor WebAssembly模板以支持这些选项,但咱们计划在.NET Core 3.0发布以后这样作。

要建立启用了身份验证的新Blazor应用程序:

  1. 建立一个新的Blazor(服务器端)项目,而后选择连接以更改身份验证配置。例如,选择“我的用户账户”和“在应用程序中存储用户账户”以将Blazor与ASP.NET Core Identity一块儿使用:

    Blazor身份验证

  2. 运行应用程序。该应用程序包含顶行中的连接,用于注册为新用户并登陆。

    Blazor身份验证运行

  3. 选择“注册”连接以注册新用户。

    Blazor认证寄存器

  4. 选择“应用迁移”以将ASP.NET Core Identity迁移应用于数据库。

    Blazor身份验证应用迁移

  5. 你如今应该登陆了。

    Blazor身份验证登陆

  6. 选择您的用户名以编辑您的用户我的资料。

    Blazor身份验证编辑配置文件

在Blazor应用程序中,Startup使用标准ASP.NET Core中间件在类中配置身份验证和受权。

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapBlazorHub();
    endpoints.MapFallbackToPage("/_Host");
});

使用ASP.NET Core Identity时,全部与身份相关的UI问题都由框架提供的默认身份UI处理。

services.AddDefaultIdentity<IdentityUser>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

应用程序顶行中的身份验证相关连接使用新的内置AuthorizeView组件呈现,该组件根据身份验证状态显示不一样的内容。

LoginDisplay.razor

<AuthorizeView>
    <Authorized>
        <a href="Identity/Account/Manage">Hello, @context.User.Identity.Name!</a>
        <a href="Identity/Account/LogOut">Log out</a>
    </Authorized>
    <NotAuthorized>
        <a href="Identity/Account/Register">Register</a>
        <a href="Identity/Account/Login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

AuthorizeView组件仅在受权用户时显示其子内容。可替代地,AuthorizeView采用参数用于指定不一样模板当用户是AuthorizedNotAuthorized,或Authorizing。当前的身份验证状态经过隐式context参数传递给这些模板。您还能够指定AuthorizeView用户必须知足的特定角色或受权策略才能查看受权视图。

要受权访问Blazor应用程序中的特定页面,请使用普通的[authorize]属性。可使用新的@attribute指令将[authorize]属性应用于组件。。

@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
@page "/fetchdata"

要指定在未受权用户或仍处于受权处理时须要受权的页面上显示的内容,请使用组件上的NotAuthorizedContentAuthorizingContent参数Router。这些Router参数仅在此版本的客户端Blazor中提供支持,但在未来的更新中将为服务器端Blazor启用它们。

AuthenticationStateProvider不管是在服务器上运行仍是在浏览器中运行客户端,新服务都会以统一的方式使Blazor应用程序可使用身份验证状态。在服务器端Blazor应用程序中AuthenticationStateProvider,用户从HttpContext创建与服务器的链接的表面。客户端Blazor应用程序能够根据应用程序配置自定义AuthenticationStateProvider。例如,它能够经过查询服务器上的端点来检索当前用户信息。

Task<AuthenticationState>使用该CascadingAuthenticationState组件将身份验证状态做为级联值提供给应用程序。而后,AuthorizeViewRouter组件使用此级联值来受权对UI的特定部分的访问。

App.razor

<CascadingAuthenticationState>
    <Router AppAssembly="typeof(Startup).Assembly">
        <NotFoundContent>
            <p>Sorry, there's nothing at this address.</p>
        </NotFoundContent>
    </Router>
</CascadingAuthenticationState>

Razor类库中的静态资产

Razor类库如今能够包含静态资源,如JavaScript,CSS和图像。而后,能够经过引用Razor类库项目或经过包引用将这些静态资产包含在ASP.NET Core应用程序中。

要在Razor类库中包含静态资源,请将一个wwwroot文件夹添加到Razor类库中,并在该文件夹中包含全部必需的文件。

当具备静态资产的Razor类库被引用为项目引用或做为包时,来自库的静态资源在路径前缀*_content / {LIBRARY NAME} /*下可供应用程序使用。静态资源保留在其原始文件夹中,Razor类库中静态资产内容的任何更改都会反映在应用程序中而不进行重建。

发布应用程序后,全部引用的Razor类库中的伴随资源将以相同的前缀复制到已发布应用程序的wwwroot文件夹中。

要尝试使用Razor类库中的静态资源:

  1. 建立默认的ASP.NET Core Web App。

    dotnet new webapp -o WebApp1
  2. 建立一个Razor类库并从Web应用程序引用它。

    dotnet new razorclasslib -o RazorLib1
    dotnet add WebApp1 reference RazorLib1
  3. wwwroot文件夹添加到Razor类库,并包含一个JavaScript文件,该文件将简单消息记录到控制台。

    cd RazorLib1
    mkdir wwwroot

    hello.js

    console.log("Hello from RazorLib1!");
  4. 从Web应用程序中的Index.cshtml引用脚本文件。

    <script src="_content/RazorLib1/hello.js"></script>
  5. 运行应用程序并在浏览器控制台中查找输出。

    Hello from RazorLib1!

项目如今默认使用System.Text.Json

如今,新的ASP.NET Core项目将默认使用System.Text.Json进行JSON处理。在此版本中,咱们从项目模板中删除了Json.NET(Newtonsoft.Json)。要启用对使用Json.NET的支持,请将Microsoft.AspNetCore.Mvc.NewtonsoftJson包添加到项目中,并AddNewtonsoftJson()Startup.ConfigureServices方法中添加对如下代码的调用。例如:

services.AddMvc()
    .AddNewtonsoftJson();

证书和Kerberos身份验证

预览6为ASP.NET Core带来了证书和Kerberos身份验证。

证书身份验证要求您将服务器配置为接受证书,而后在Startup.Configure中添加身份验证中间件和在Startup.ConfigureServices中配置证书身份验证服务。

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(
        CertificateAuthenticationDefaults.AuthenticationScheme)
            .AddCertificate();
    // All the other service configuration.
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseAuthentication();
    // All the other app configuration.
}

证书身份验证选项包括接受自签名证书,检查证书吊销以及检查提供的证书中是否包含正确的使用标记的功能。默认用户主体是从证书属性构造的,其中包含一个容许您补充或替换主体的事件。有关如何为证书身份验证配置公共主机的全部选项和说明,请参阅文档

咱们还将“Windows身份验证”扩展到Linux和macOS上。之前,此身份验证类型仅限于IIS和HttpSys,但如今Kestrel可使用Microsoft.AspNetCore.Authentication.Negotiate nuget包在Windows,Linux和macOS上为Windows域加入的主机使用Negotiate,Kerberos和NTLM。与配置身份验证应用程序范围的其余身份验证服务同样,而后配置服务:

public void ConfigureServices(IServiceCollection services)
{ 
    services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
        .AddNegotiate();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseAuthentication();
    // All the other app configuration.
}

必须正确配置主机。Windows主机必须将SPN添加到托管应用程序的用户账户。必须将Linux和macOS计算机加入域,而后必须为Web进程建立SPN,以及在主机上生成和配置的keytab文件。文档中给出了完整的说明。

SignalR自动从新链接

此预览版本现已经过npm install @aspnet/signalr@next 和.NET Core SignalR Client方式进行提供,包括一个新的自动从新链接功能。在这个版本中,咱们已经将withAutomaticReconnect()方法添加到了HubConnectionBuilder。默认状况下,客户端将尝试当即从新链接,并在二、10和30秒后从新链接。参与自动从新链接是可选的,但经过这种新方法很简单。

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chatHub")
    .withAutomaticReconnect()
    .build();

经过将一系列基于毫秒的持续时间传递给该方法,您能够很是精细地了解从新链接尝试如何随时间发生。

.withAutomaticReconnect([0, 3000, 5000, 10000, 15000, 30000])
//.withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior

或者,您能够传递自定义从新链接策略的实现,该策略可让您彻底控制。

若是30秒后从新链接失败(或您设置的最大值),客户端会假定链接处于脱机状态,并中止尝试从新链接。在这些从新链接尝试期间,您将但愿更新应用程序UI,以向用户提供尝试从新链接的提示。

从新链接事件处理程序

为了简化这一过程,咱们将SignalR客户端API扩展为包含onreconnectingonreconnected事件处理程序。第一个处理程序onreconnecting为开发人员提供了一个禁用UI或让用户知道应用程序处于脱机状态的好机会。

connection.onreconnecting((error) => {
    const status = `Connection lost due to error "${error}". Reconnecting.`;
    document.getElementById("messageInput").disabled = true;
    document.getElementById("sendButton").disabled = true;
    document.getElementById("connectionStatus").innerText = status;
});

一样,onreconnected处理程序使开发人员有机会在从新创建链接后更新UI。

connection.onreconnected((connectionId) => {
    const status = `Connection reestablished. Connected.`;
    document.getElementById("messageInput").disabled = false;
    document.getElementById("sendButton").disabled = false;
    document.getElementById("connectionStatus").innerText = status;
});

了解有关自定义和处理从新链接的详细信息

预览版本中已经部分记录了自动从新链接。请访问https://aka.ms/signalr/auto-reconnect,查看有关该主题的更深刻的文档,以及有关使用的更多示例和详细信息。

托管gRPC客户端

在以前的预览中,咱们依靠Grpc.Core库来获取客户端支持。HttpClient在此预览中添加HTTP / 2支持使咱们可以引入彻底托管的gRPC客户端。

要开始使用新客户端,请添加包引用Grpc.Net.Client,而后您能够建立新客户端。

var httpClient = new HttpClient() { BaseAddress = new Uri("https://localhost:5001") };
var client = GrpcClient.Create<GreeterClient>(httpClient);

gRPC客户端工厂

基于咱们介绍的固定模式HttpClientFactory,咱们添加了一个gRPC客户端工厂,用于在项目中建立gRPC客户端实例。咱们添加了两种工厂:Grpc.Net.ClientFactoryGrpc.AspNetCore.Server.ClientFactory

Grpc.Net.ClientFactory设计用于non-ASP.NET应用模型的使用(如工人服务)仍然使用Microsoft.Extensions.*原语不会对ASP.NET核心的依赖。

Grpc.Net.ClientFactory设计用于仍使用Microsoft.Extensions.*基元(不依赖于ASP.NET核心)的非ASP.NET应用程序模型(如Worker Services)。

在执行服务到服务通讯的应用程序中,咱们常常发现大多数服务器也是使用其余服务的客户端。在这些状况下,咱们建议使用Grpc.AspNetCore.Server.ClientFactory它具备自动传播gRPC截止日期和取消令牌的功能。

要使用客户端工厂,请在将如下代码添加到configureServices()以前,将适当的包引用添加到项目(Grpc.AspNetCore.Server.FactoryGrpc.Net.ClientFactory)。

services
    .AddGrpcClient<GreeterClient>(options =>
    {
        options.BaseAddress = new Uri("https://localhost:5001");
    });

gRPC拦截器

gRPC公开了一种机制来拦截客户端和服务器上的RPC调用。拦截器能够与现有的HTTP中间件结合使用。与HTTP中间件不一样,拦截器容许您在序列化以前(在客户端上)和反序列化以后(在服务器上)访问实际的请求/响应对象,反之亦然。全部中间件都在请求端的拦截器以前运行,反之亦然。

客户端拦截器

与客户端工厂一块儿使用时,能够添加客户端拦截器,以下所示。

services
    .AddGrpcClient<GreeterClient>(options =>
    {
        options.BaseAddress = new Uri("https://localhost:5001");
    })
    .AddInterceptor<CallbackInterceptor>();

服务器拦截器

服务器拦截器能够ConfigureServices()以下所示进行注册。

services
    .AddGrpc(options =>
    {
        // This registers a global interceptor
        options.Interceptors.Add<MaxStreamingRequestTimeoutInterceptor>(TimeSpan.FromSeconds(30));
    })
    .AddServiceOptions<GreeterService>(options =>
    {
        // This registers an interceptor for the Greeter service
        options.Interceptors.Add<UnaryCachingInterceptor>();
    });

有关如何编写拦截器的示例,请查看grpc-dotnet repo中的这些示例

给予反馈

咱们但愿您喜欢ASP.NET Core和Blazor预览版中的新功能!请经过在GitHub上提交问题告诉咱们您的想法。(再次声明,本文大多内容翻译自:ASP.NET首席项目经理Daniel Roth的介绍,所以才会有这段话。)

感谢您试用ASP.NET Core和Blazor!

原文地址:https://devblogs.microsoft.com/aspnet/asp-net-core-and-blazor-updates-in-net-core-3-0-preview-6/