.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的介紹。
注:英語能力好的可以直接到文章末尾檢視英文連結進行閱讀。
作者:依樂祝
本文連結:https://www.cnblogs.com/yilezhu/p/11031441.html
以下是此預覽版中的新增功能列表:
- 新Razor特性:@attribute,@code,@key,@namespace,@functions中的標記
- Blazor指令屬性
- Blazor應用程式的身份驗證和授權支援
- Razor類庫中的靜態資產
- Json.NET不再在專案模板中引用
- 證書和Kerberos身份驗證
- SignalR自動重新連線
- 託管gRPC客戶端
- gRPC客戶端工廠
- gRPC攔截器
有關其他詳細資訊和已知問題,請參閱發行說明。
開始
要在.NET Core 3.0 Preview 6中開始使用ASP.NET Core,請安裝.NET Core 3.0 Preview 6 SDK
如果您在Windows上使用Visual Studio進行的話,則還需要安裝Visual Studio 2019的最新預覽。
對於最新的客戶端Blazor模板,還可以從Visual Studio Marketplace 安裝最新的Blazor擴充套件。
升級現有專案
要將現有的ASP.NET Core應用程序升級到.NET Core 3.0 Preview 6,請按照ASP.NET Core文件中的遷移步驟進行操作。
另請參閱ASP.NET Core 3.0 中的重大更改的完整列表。
要將現有的ASP.NET Core 3.0 Preview 5專案升級到Preview 6:
- 更新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使用新資料完全重建自己,這是浪費的,有時甚至會導致使用者可見問題(例如,輸入焦點意外丟失)。
通過使用@key
diffing演算法新增鍵可以關聯新舊元素或元件。
@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應用程式:
建立一個新的Blazor(伺服器端)專案,然後選擇連結以更改身份驗證配置。例如,選擇“個人使用者帳戶”和“在應用程式中儲存使用者帳戶”以將Blazor與ASP.NET Core Identity一起使用:
執行應用程式。該應用程式包含頂行中的連結,用於註冊為新使用者並登入。
選擇“註冊”連結以註冊新使用者。
選擇“應用遷移”以將ASP.NET Core Identity遷移應用於資料庫。
你現在應該登入了。
選擇您的使用者名稱以編輯您的使用者個人資料。
在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
採用引數用於指定不同模板當用戶是Authorized
,NotAuthorized
,或Authorizing
。當前的身份驗證狀態通過隱式context
引數傳遞給這些模板。您還可以指定AuthorizeView
使用者必須滿足的特定角色或授權策略才能檢視授權檢視。
要授權訪問Blazor應用程式中的特定頁面,請使用普通的[authorize]
屬性。可以使用新的@attribute
指令將[authorize]
屬性應用於元件。。
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
@page "/fetchdata"
要指定在未授權使用者或仍處於授權處理時需要授權的頁面上顯示的內容,請使用元件上的NotAuthorizedContent
和AuthorizingContent
引數Router
。這些Router
引數僅在此版本的客戶端Blazor中提供支援,但在將來的更新中將為伺服器端Blazor啟用它們。
AuthenticationStateProvider
無論是在伺服器上執行還是在瀏覽器中執行客戶端,新服務都會以統一的方式使Blazor應用程式可以使用身份驗證狀態。在伺服器端Blazor應用程式中AuthenticationStateProvider
,使用者從HttpContext
建立與伺服器的連線的表面。客戶端Blazor應用程式可以根據應用程式配置自定義AuthenticationStateProvider
。例如,它可以通過查詢伺服器上的端點來檢索當前使用者資訊。
Task<AuthenticationState>
使用該CascadingAuthenticationState
元件將身份驗證狀態作為級聯值提供給應用程式。然後,AuthorizeView
和Router
元件使用此級聯值來授權對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類庫中的靜態資源:
建立預設的ASP.NET Core Web App。
dotnet new webapp -o WebApp1
建立一個Razor類庫並從Web應用程式引用它。
dotnet new razorclasslib -o RazorLib1 dotnet add WebApp1 reference RazorLib1
將wwwroot資料夾新增到Razor類庫,幷包含一個JavaScript檔案,該檔案將簡單訊息記錄到控制檯。
cd RazorLib1 mkdir wwwroot
hello.js
console.log("Hello from RazorLib1!");
從Web應用程式中的Index.cshtml引用指令碼檔案。
<script src="_content/RazorLib1/hello.js"></script>
執行應用程式並在瀏覽器控制檯中查詢輸出。
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
。預設情況下,客戶端將嘗試立即重新連線,並在2、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擴充套件為包含onreconnecting
和onreconnected
事件處理程式。第一個處理程式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.ClientFactory
和Grpc.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.Factory
或Grpc.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/