.NET開發(fā)人員的Blazor的入門指南(.net core blazor)
Blazor為數(shù)百萬(wàn).NET開發(fā)人員帶來(lái)了WebAssembly的世界,允許他們編寫在瀏覽器上運(yùn)行的C#。
多年來(lái),如果您想編寫代碼以在瀏覽器中運(yùn)行,您的選擇是JavaScript或JavaScript。對(duì)于某些瀏覽器上的幾個(gè)短暫時(shí)期,您可以使用其他語(yǔ)言,但它們并不重要:IE上的VBScript和特殊版Chrome上的Dart。
還有一些語(yǔ)言可以編譯成JavaScript(TypeScript,CoffeeScript,…),但它們?nèi)匀皇钦嬲腏avaScript。JavaScript單一文化的日子隨著WebAssembly(Wasm)的出現(xiàn)而出現(xiàn)。對(duì)于.NET開發(fā)人員,Wasm以Blazor的形式到達(dá)。
什么是WebAssembly?
WebAssembly是瀏覽器中支持運(yùn)行Wasm字節(jié)碼的虛擬機(jī)規(guī)范。這種二進(jìn)制格式允許比典型的JavaScript更快的執(zhí)行,因此性能可以比純JavaScript更好。有許多編譯器可以輸出這種格式,包括LLVM。因此,現(xiàn)在可以用C 編寫代碼,將其編譯為Wasm程序集,將其發(fā)送到瀏覽器,然后直接運(yùn)行。
瀏覽器對(duì)Wasm的支持非常廣泛。即使在較舊的瀏覽器上,也可以通過(guò)asm.js獲得支持,盡管性能閾值較低。
.NET如何支持Wasm
許多語(yǔ)言已經(jīng)開始通過(guò)輸出Wasm程序集將其語(yǔ)言帶到WebAssembly的項(xiàng)目。微軟采用的方法與大多數(shù)其他平臺(tái)略有不同。通常,您會(huì)將輸出二進(jìn)制文件編譯為Wasm,然后直接在瀏覽器中加載它們。但是,.NET二進(jìn)制文件已經(jīng)采用通用語(yǔ)言設(shè)計(jì),可以在.NET Framework上運(yùn)行:中間語(yǔ)言。因此,如果不是將代碼編譯為Wasm,而是將框架本身編譯為Web Assembly,他們可以解釋他們已經(jīng)使用這個(gè)框架的Wasm版本的相同二進(jìn)制文件。
當(dāng)然,.NET Standard統(tǒng)一了.NET Framework的幾種不同風(fēng)格。作為WebAssembly運(yùn)行的版本實(shí)際上是Mono。有人擔(dān)心使用Mono而不是.NET Core,我可以理解。使用多個(gè).NET框架有點(diǎn)煩人,但各種框架之間的標(biāo)準(zhǔn)化工作非常好。
什么是Blazor?
我想告訴人們Blazor并將整個(gè).NET Framework編譯為Wasm是完全瘋狂的。事實(shí)上Blazor是Steve Sanderson的一個(gè)項(xiàng)目,他之前曾創(chuàng)建過(guò)一些偉大的瘋狂項(xiàng)目:xVal,Knockout,JavaScript服務(wù)。因此,隨著瘋狂項(xiàng)目的進(jìn)行,我們掌握得非常好。
Blazor是一個(gè)高度實(shí)驗(yàn)性的項(xiàng)目,它將ASP.NET的感覺帶給了Wasm。您使用您識(shí)別并記住的所有工具在C#中編寫代碼。您仍然可以使用過(guò)去的相同工具進(jìn)行單元測(cè)試。您仍然可以使用相同的日志記錄工具。實(shí)際上,您可以掌握所有C#知識(shí)并編寫Web應(yīng)用程序。
服務(wù)器端VS. 客戶端
目前Blazor有兩種型號(hào):客戶端和服務(wù)器端型號(hào)。客戶端版本實(shí)際上通過(guò)Wasm在瀏覽器中運(yùn)行,并且在那里完成對(duì)DOM的更新,而服務(wù)器端模型在服務(wù)器上保留DOM的模型并使用以下方式在瀏覽器和服務(wù)器之間來(lái)回傳輸差異。 SignalR管道。事實(shí)上,服務(wù)器端更有可能成為一個(gè)真正的產(chǎn)品,并且已經(jīng)承諾用于ASP.NET Core 3,這聽起來(lái)好像是一年之后。
這真的可以表現(xiàn)嗎?
有許多因素使得以這種方式部署的應(yīng)用程序的性能看起來(lái)很糟糕。第一個(gè)是.NET Framework的大尺寸。將.NET框架的加載捆綁到每個(gè)網(wǎng)站加載中是很大的。但是,已有技術(shù)可以使其更易于管理。如果框架是從CDN傳遞的,瀏覽器可以緩存框架,甚至可以在站點(diǎn)之間重用它。稍微更奇特的方法是使用樹搖動(dòng)來(lái)移除應(yīng)用程序未使用的框架的巨大條帶。
該項(xiàng)目中最大的資產(chǎn)是mono.wasm文件,即869KB。項(xiàng)目中使用的各種DLL總計(jì)幾乎達(dá)到一兆字節(jié)。
這是很多下載的框架代碼,幾乎沒有任何實(shí)際功能的2MB,所以這確實(shí)是一個(gè)問(wèn)題。
接下來(lái),.NET代碼可以在傳送到瀏覽器時(shí)以高效的方式運(yùn)行并編譯成奇怪的匯編語(yǔ)言嗎?目前,編譯為Wasm的C項(xiàng)目似乎有50%的減速。顯然,在瀏覽器中運(yùn)行框架會(huì)有一些開銷,但我們還不確定它將在何處著陸。正在努力改進(jìn)和優(yōu)化速度,并且當(dāng)它達(dá)到生產(chǎn)性能時(shí)可能是合理的。很多這種表現(xiàn)只是因?yàn)閃asm通常比JavaScript更有效,盡管這樣的基準(zhǔn)測(cè)試非常困難。
最終結(jié)果是,Wasm似乎比典型的JavaScript Web應(yīng)用程序具有更大的啟動(dòng)成本,但是一旦您啟動(dòng)并運(yùn)行任何類型的計(jì)算復(fù)雜操作都會(huì)更快。
Blazor項(xiàng)目入門
第一步是確保您在Visual Studio和.NET Core方面擁有的所有內(nèi)容都是最新的。在撰寫本文時(shí),我使用的是.NET Core工具版本2.1.500。接下來(lái),有一些工具可以讓Blazor更加愉快。第一個(gè)是可以通過(guò)運(yùn)行安裝的模板集合:
dotnet new -i Microsoft.AspNetCore.Blazor.Templates
從命令行。我們將在本文中使用完整的Visual Studio,但您可以使用VS Code或vi或任何您想要的。在Visual Studio中,安裝Blazor擴(kuò)展,官方Blazor文檔建議運(yùn)行至少VS 15.9,但我運(yùn)行15.8沒有問(wèn)題。
有了所有這些,我們就可以開始一個(gè)全新的Blazor項(xiàng)目。在新項(xiàng)目對(duì)話框中,選擇一個(gè)新的ASP.NET Core項(xiàng)目。在模板選擇對(duì)話框中,有三個(gè)基于Blazor的模板:
- Blazor – 完整的客戶端Blazor應(yīng)用程序,沒有任何服務(wù)器端組件。這適用于部署到S3或Azure Blob存儲(chǔ)等靜態(tài)主機(jī)。
- Blazor(ASP.NET Core托管) – 一個(gè)客戶端應(yīng)用程序,其服務(wù)器端為Blazor提供服務(wù),并且還提供放置服務(wù)器端API的位置。
- Blazor(ASP.NET核心中的服務(wù)器端) – 服務(wù)器端應(yīng)用程序,通過(guò)SignalR從服務(wù)器更新DOM
出于我們的目的,我們將使用ASP.NET Core托管變體。請(qǐng)記住,這個(gè)將DLL發(fā)送到瀏覽器的版本不會(huì)出現(xiàn)在ASP.NET Core 3的官方支持中,至少目前還沒有。
探索守則
從該模板創(chuàng)建的解決方案有三個(gè)項(xiàng)目。
- 客戶端包含在瀏覽器上運(yùn)行的代碼。
- 服務(wù)器是服務(wù)器端代碼。默認(rèn)項(xiàng)目有一個(gè)簡(jiǎn)單的控制器,可以返回有關(guān)天氣的一些數(shù)據(jù)。
- 共享包含在客戶端和服務(wù)器端使用的代碼。像模特這樣的東西是一件很棒的事情。驗(yàn)證元數(shù)據(jù)在這里也可能是一個(gè)很好的補(bǔ)充,因?yàn)樗馕吨憧梢詰?yīng)用相同的驗(yàn)證邏輯客戶端和服務(wù)器端。
最有趣的代碼是在Client項(xiàng)目中,因?yàn)镾erver項(xiàng)目主要只是一個(gè)標(biāo)準(zhǔn)的ASP.NET Core應(yīng)用程序。您將注意到客戶端結(jié)構(gòu)中的第一件事是它與ASP.NET Core項(xiàng)目的結(jié)構(gòu)非常相似。
有一個(gè)Program.cs作為引導(dǎo)程序,就像你在ASP.NET Core應(yīng)用程序中看到的那樣。Startup.cs包含設(shè)置服務(wù)和配置應(yīng)用程序的代碼。這種相似性允許您將更多的ASP.NET核心知識(shí)帶到Blazor世界。HTML文件也都具有您熟悉和喜愛的相同.cshtml擴(kuò)展名。打開其中一個(gè)文件可以發(fā)現(xiàn)它們使用的是與MVC相同的Razor語(yǔ)法,直到2008年。
最有趣的cshtml文件是FetchData.cshtml。
我們可以從FetchData.cshtml學(xué)到什么
@using Blazor2.Shared
@page “/fetchdata”
@inject HttpClient Http
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p><em>Loading…</em></p>
}
else
{
<table class=”table”>
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@functions {
WeatherForecast[] forecasts;
protected override async Task OnInitAsync()
{
forecasts = await Http.GetJsonAsync<WeatherForecast[]>(“api/SampleData/WeatherForecasts”);
}
}
在這個(gè)文件中,你會(huì)發(fā)現(xiàn)一些有趣的部分。@page指令用于提供路由器可用于將人們引導(dǎo)到頁(yè)面的位置。@inject允許注入服務(wù)。HttpClient是默認(rèn)注冊(cè)的,不需要在Startup.cs中顯式輸入。這里有趣的是,這里使用的HttpClient與您在服務(wù)器端使用的HttpClient不同,因?yàn)樵赪asm沙箱中不允許訪問(wèn)原始套接字,就像在JavaScript中不允許這樣。最后,您會(huì)注意到有一個(gè)分支基于預(yù)測(cè)是否為空。Blazor實(shí)際監(jiān)視此屬性,當(dāng)它更改時(shí),將重新運(yùn)行頁(yè)面呈現(xiàn)。變更檢測(cè)內(nèi)置于。
擴(kuò)展項(xiàng)目
為了將項(xiàng)目擴(kuò)展到完全成熟的應(yīng)用程序,您只需添加服務(wù)和cshtml頁(yè)面即可。只要您注意結(jié)構(gòu)并匹配擴(kuò)展ASP.NET Core應(yīng)用程序的方式,您就應(yīng)該保持良好的信譽(yù)。您可以通過(guò)NuGet添加對(duì)外部庫(kù)的引用,其中大部分都可以正常工作。但是,您應(yīng)該記住,每次添加增加有效負(fù)載大小的包時(shí),都需要將其發(fā)送到客戶端。由于基本軟件包的容量接近2MB,因此每下載的內(nèi)容都要多得多。
限制
顯然,在瀏覽器中可以執(zhí)行的操作存在一些限制。在Wasm中運(yùn)行的所有內(nèi)容都在JavaScript沙箱中運(yùn)行,這意味著您無(wú)法直接訪問(wèn)磁盤或網(wǎng)絡(luò)等內(nèi)容。因此,使用SQLClient直接與數(shù)據(jù)庫(kù)通信等許多功能都無(wú)法工作(無(wú)論如何這也是一個(gè)糟糕的想法)。庫(kù)可能包含嘗試寫入臨時(shí)文件的功能,這些功能無(wú)效。在計(jì)劃如何測(cè)試應(yīng)用程序時(shí),請(qǐng)記住這些限制。
點(diǎn)擊原生JavaScript代碼
Blazor和Wasm的一個(gè)非常好的部分是,它可以與JavaScript API進(jìn)行交互。因此,如果您想通過(guò)地理定位API進(jìn)行地理定位,您可以安裝Blazor.Geolocation(新近更新Blazor 0.7,BTW)等軟件包,它就可以正常工作。復(fù)雜的編組是為了映射JavaScript和.NET數(shù)據(jù)類型來(lái)回完成所有這些都是由Blazor完成的。在大多數(shù)情況下,您可以從.NET代碼輕松地從JavaScript和JavaScript方法調(diào)用.NET方法。心靈爆炸!
在Blazor.Geolocation示例中,要從瀏覽器的JavaScript上下文中獲取位置信息,您只需要在cshtml中注入位置服務(wù)并運(yùn)行
location = await locationService.GetLocationAsync();
該軟件包負(fù)責(zé)處理從瀏覽器獲取位置信息的異步性質(zhì)。其他JavaScript API可以類似地包裝。
您可以在Blazor文檔中詳細(xì)了解如何與JavaScript 交互。
出現(xiàn)問(wèn)題時(shí)調(diào)試Blazor
調(diào)試故事目前并不出色。使用服務(wù)器端Blazor,在Visual Studio中一切都是F5可調(diào)試的,但是一旦你轉(zhuǎn)到客戶端,調(diào)試故事就沒有完全充實(shí)。Chrome中的“來(lái)源”選項(xiàng)卡包含一個(gè)令人困惑的文件陣列和Wasm函數(shù),此時(shí)無(wú)法輕松調(diào)試。最終,可能會(huì)為所有這些提供源映射支持,并且體驗(yàn)應(yīng)該更好。但是,目前,編譯器無(wú)法輸出映射。
網(wǎng)絡(luò)流量可以像調(diào)整任何其他網(wǎng)絡(luò)流量一樣進(jìn)行調(diào)試,例如在前綴中。同樣,服務(wù)器端仍然是標(biāo)準(zhǔn)的ASP.NET核心應(yīng)用程序,因此它可以從Retrace或Prefix的檢測(cè)中受益。在這方面,至少調(diào)試和分析的故事非常好。
WebAssembly在哪里?
只有傻瓜才會(huì)對(duì)未來(lái)作出陳述,所以我在這里:我認(rèn)為WebAssembly有一個(gè)光明的未來(lái)。為無(wú)數(shù)語(yǔ)言和編程范例解鎖Web開發(fā)將產(chǎn)生一些非常有趣的新框架。WebAssembly的速度也適用于從游戲到AI的各種代碼。