.NET 6 Preview 3 中 ASP.NET Core 的更新和改进
原文:bit.ly/2Qb56NP
作者:Daniel Roth
譯者:精致碼農(nóng)-王亮
.NET 6 預覽版 3 現(xiàn)已推出,其中包括許多對新的 ASP.NET Core 改進。以下是本次預覽版的新內(nèi)容:
更小的 SignalR、Blazor Server、MessagePack 腳本文件
啟用 Redis 分析會話
HTTP/3 端點 TLS 配置
初步 .NET 熱重載支持
Razor 編譯器不再生成單獨的視圖 Assembly
IIS 中的淺拷貝支持
適用于 SignalR C++ 客戶端的 Vcpkg 端口
減少閑置 TLS 連接的內(nèi)存占用量
從 SlabMemoryPool 中移除板塊
用于 WPF 和 Windows 窗體的 BlazorWebView 控件
1開始
要在.NET 6 Preview 3 中開始使用 ASP.NET Core,請安裝 .NET 6 SDK[1]。
如果你在 Windows 上使用 Visual Studio,我們建議安裝 Visual Studio 2019 16.10 的最新預覽版。如果你在 macOS 上,我們建議安裝 Visual Studio 2019 for Mac 8.10 的最新預覽版。
2升級現(xiàn)有項目
要將現(xiàn)有的 ASP.NET Core 應用程序從 .NET 6 Preview 2 升級到 .NET 6 Preview 3:
更新所有Microsoft.AspNetCore.*包引用至6.0.0-preview.3.*。
更新所有Microsoft.Extensions.*包引用至6.0.0-preview.3.*。
查看 ASP.NET Core for .NET 6 中的完整中斷性更改列表[2]。
3更小的腳本文件
得益于 Ben Adams 的社區(qū)貢獻,SignalR、MessagePack 和 Blazor Server 腳本現(xiàn)在明顯變小了,下載體積減少,瀏覽器解析和編譯 JavaScript 的次數(shù)減少,啟動速度加快。
這項工作帶來的下載體積減少是非常驚人的:
| signalr.min.js | 130 KB | 39 KB | 70% | 10 KB |
| blazor.server.js | 212 KB | 116 KB | 45% | 28 KB |
現(xiàn)在你也只需要為 MessagePack 提供@microsoft/signalr-protocol-msgpack包,而不需要包含 msgpack5。這意味著你只需要額外的 29 KB 而不是之前的 140 KB 來使用 MessagePack 而不是 JSON。
下面說下我們是如何減少體積的:
更新 TypeScript 和依賴關系到最新版本.
將 uglify-js 換成了 terser,這是 webpack 的默認版本,支持新的 JavaScript 語言特性(比如class)。
將 SignalR 模塊標記為"sideEffects":false,這樣 tree-shaking 就更有效了。
丟棄了 "es6-promise/dist/es6-promise.auto.js"的多邊填充。
更改 TypeScript 為輸出es2019而不是es5,并放棄了es2015.promise和es2015.iterable的 polyfill。
從@msgpack/msgpack移到msgpack5,因為它需要更少的 polyfills,并且是 TypeScript 和模塊感知的。
你可以在 GitHub 上 Ben 的 PR[3] 中找到更多關于這些變化的細節(jié)。
4啟用 Redis 分析會話
我們接受了 Gabriel Lucaci 的社區(qū)貢獻,在此預覽版中使用Microsoft.Extensions.Caching.StackExchangeRedis啟用 Redis 分析會話。關于 Redis 分析的更多細節(jié),請參見官方文檔[4]。該 API 的使用方法如下:
services.AddStackExchangeRedisCache(options => {options.ProfilingSession = () => new ProfilingSession(); })5HTTP/3 端點 TLS 配置
HTTP/3 與現(xiàn)有的 HTTP 協(xié)議相比具有許多優(yōu)勢,包括更快的連接設置,以及在低質(zhì)量網(wǎng)絡上的性能改進。
在此預覽版中,新增了使用UseHttps在單個 HTTP/3 端口上配置 TLS 證書的功能。這使得 Kestrel 的 HTTP/3 端點配置與 HTTP/1.1 和 HTTP/2 一致。
.ConfigureKestrel((context, options) => {options.EnableAltSvc = true;options.Listen(IPAddress.Any, 5001, listenOptions =>{listenOptions.Protocols = HttpProtocols.Http3;listenOptions.UseHttps(httpsOptions =>{httpsOptions.ServerCertificate = LoadCertificate();});}); })6初步 .NET 熱重載支持
現(xiàn)在,使用dotnet watch的 ASP.NET Core 和 Blazor 項目可以獲得對 .NET 熱重載的早期支持。.NET 熱重載可以在不重新啟動應用程序和不丟失應用程序狀態(tài)的情況下將代碼更改應用到你正在運行的應用程序中。
要在現(xiàn)有的基于 .NET 6 的 ASP.NET Core 項目中試用熱重載,請將"hotReloadProfile": "aspnetcore"屬性添加到你的launchSettings.json文件中。對于 Blazor WebAssembly 項目,使用"blazorwasm"熱重載配置文件。
使用dotnet watch運行項目。下面的輸出表明熱重載已經(jīng)啟用:
watch : Hot reload enabled. For a list of supported edits, see https://aka.ms/dotnet/hot-reload. Press "Ctrl + R" to restart.在任何時候你想強制應用程序重新構(gòu)建和重啟,你可以在控制臺輸入Ctrl+R來實現(xiàn)。
現(xiàn)在你可以開始對你的代碼進行編輯了。當你保存代碼更改時,相應的更改幾乎會在瞬間自動熱重載到運行中的應用程序中。運行中的應用程序中的任何狀態(tài)都會被保留。
你也可以對你的 CSS 文件進行熱重載更改,而不需要刷新瀏覽器:
有一些代碼更改不支持 .NET 執(zhí)重載。你可以在文檔[5]中找到支持的代碼編輯列表。在 Blazor WebAssembly 中,目前只支持方法體替換。我們正在努力擴展 .NET 6 中支持的編輯集。當dotnet watch檢測到無法使用熱重載應用的更改時,它就會退回重新構(gòu)建和重新啟動應用程序。
這只是 .NET 6 中熱重載支持的開始。桌面和移動應用程序的熱重載支持將很快在即將到來的預覽版中提供,以及在 Visual Studio 中集成熱重載。
7IIS 中的淺拷貝支持
我們在 IIS 的 ASP.NET Core 模塊中添加了一個新功能,以增加對淺拷貝應用程序程序集的支持。目前,.NET 在 Windows 上運行時鎖定了應用程序的二進制文件,使得在應用程序仍在運行時無法替換二進制文件。雖然我們的建議仍然是使用應用程序脫機文件,但我們認識到在某些情況下(例如 FTP 部署)不可能這樣做。
在這種情況下,你可以通過自定義 ASP.NET Core 模塊處理程序設置來啟用淺拷貝。在大多數(shù)情況下,ASP.NET Core 應用程序的web.config不在源代碼版本控制中,你可以修改它(它們通常是由 SDK 生成的)。你可以添加這個web.config示例來開始。
<?xml version="1.0" encoding="utf-8"?> <configuration><!-- To customize the asp.net core module uncomment and edit the following p.For more info see https://go.microsoft.com/fwlink/?linkid=838655 --><system.webServer><handlers><remove?name="aspNetCore"/><add?name="aspNetCore"?path="*"?verb="*"?modules="AspNetCoreModulev2"?resourceType="Unspecified"/></handlers><aspNetCore?processPath="%LAUNCHER_PATH%"?arguments="%LAUNCHER_ARGS%"?stdoutLogEnabled="false"?stdoutLogFile=".\logs\stdout"><handlerSettings><handlerSetting?name="experimentalEnableShadowCopy"?value="true" /><handlerSetting?name="shadowCopyDirectory"?value="../ShadowCopyDirectory/" /><!-- Only enable handler logging if you encounter issues--><!--<handlerSetting name="debugFile" value=".\logs\aspnetcore-debug.log" />--><!--<handlerSetting name="debugLevel" value="FILE,TRACE" />--></handlerSettings></aspNetCore></system.webServer> </configuration>你需要一個新版本的 ASP.NET Core 模塊來嘗試這個功能。在自托管的 IIS 服務器上,這需要新版本的托管捆綁包。在 Azure App Services 上,你需要安裝新的 ASP.NET Core 站點運行時擴展。
8適用于 SignalR C++ 客戶端的 Vcpkg 端口
Vcpkg 是一個跨平臺的 C 和 C++庫的命令行包管理器。最近,我們?yōu)?vcpkg 添加了一個移植版本,為 SignalR C++ 客戶端添加了 CMake 本地支持(也適用于 MSBuild 項目)。
你可以用下面的代碼來添加 SignalR 客戶端到你的 CMake 項目中(假設你已經(jīng)包含了 vcpkg 工具鏈文件)。
find_package(microsoft-signalr CONFIG REQUIRED) link_libraries(microsoft-signalr::microsoft-signalr)在這之后,SignalR C++ 客戶端就可以被#include并用于你的項目中,而不需要任何額外的配置。這個倉庫[6]是一個完整的使用 SignalR C++ 客戶端的 C++ 應用程序的例子。
9減少閑置 TLS 連接的內(nèi)存占用量
對于只偶爾來回發(fā)送數(shù)據(jù)的 TLS 長連接,我們已經(jīng)大大減少了 .NET 6 中 ASP.NET Core 應用程序的內(nèi)存占用。這應該有助于提高 WebSocket 服務器等場景的可擴展性。這得益于System.IO.Pipelines、SslStream和Kestrel的眾多改進。讓我們來看看促成這一方案的一些改進。
縮減 System.IO.Pipelines.Pipe 大小
對于我們建立的每一個連接,我們都會在 Kestrel 中分配兩個管道:一個是從傳輸層到應用的請求,另一個是從應用層到傳輸?shù)捻憫Mㄟ^將System.IO.Pipelines.Pipe的大小從 368 字節(jié)縮減到 264 字節(jié)(約 28.2%),我們?yōu)槊總€連接節(jié)省了 208 字節(jié)(每個 Pipe 節(jié)省 104 字節(jié))。
SocketSender 池
SocketSender 對象在運行時約為 350 字節(jié)。與其為每個連接分配一個新的 SocketSender 對象,我們可以將它們集中起來,因為發(fā)送通常非常快,我們可以減少每個連接的開銷。現(xiàn)在,我們不再為每個連接分配 350 字節(jié),而是只為每個 IOQueue 分配 350 字節(jié)(每個隊列一個,以避免爭用)。在擁有 5000 個空閑連接的 WebSocket 服務器中,我們從分配約 1.75 MB(350 字節(jié)*5000)到現(xiàn)在只分配約 2.8kb(350 字節(jié)*8)給 SocketSender 對象。
SslStream 零字節(jié)讀取
無緩沖讀取是我們已經(jīng)在 ASP.NET Core 中采用的一種技術,以避免在套接字上沒有可用數(shù)據(jù)時從內(nèi)存池中租用內(nèi)存。在這一變化之前,我們的 WebSocket 服務器有 5000 個空閑連接,在沒有 TLS 的情況下需要約 200 MB,而在有 TLS 的情況下需要約 800 MB。其中一些分配(每個連接 4k)是由于 Kestrel 在等待SslStream上的讀取完成時必須保持ArrayPool緩沖區(qū)。鑒于這些連接是空閑的,沒有一個讀取完成并將其緩沖區(qū)返回給ArrayPool,迫使ArrayPool分配更多的內(nèi)存。剩余的分配都在SslStream本身。4k 緩沖區(qū)用于 TLS 握手,32k 緩沖區(qū)用于正常讀取。在預覽版 3 中,當用戶在SslStream上執(zhí)行零字節(jié)讀取,而它又沒有可用的數(shù)據(jù)時,SslStream會在內(nèi)部對底層的封裝流執(zhí)行零字節(jié)讀取。在最好的情況下(空閑連接),這些變化導致每個連接節(jié)省了 40 Kb,同時仍然允許消費者(Kestrel)在數(shù)據(jù)可用時得到通知,而無需保留任何未使用的緩沖區(qū)。
PipeReader 零字節(jié)讀取
一旦SslStream支持無緩沖區(qū)讀取,我們就向StreamPipeReader(將Stream適配成PipeReader的內(nèi)部類型)添加了執(zhí)行零字節(jié)讀取的選項。在 Kestrel 中,我們使用StreamPipeReader將底層的SslStream適配成PipeReader,有必要在PipeReader上暴露這些零字節(jié)讀取語義。
現(xiàn)在,你可以使用以下 API 創(chuàng)建一個PipeReader,支持在任何支持零字節(jié)讀取語義的Stream上進行零字節(jié)讀取(例如SslStream、NetworkStream等)。
var reader = PipeReader.Create(stream, new StreamPipeReaderOptions(useZeroByteReads: true));10從 SlabMemoryPool 中移除板塊
為了減少堆的碎片,Kestrel 采用了一種技術,它分配了 128 KB 的內(nèi)存板塊作為其內(nèi)存池的一部分。然后,這些板塊被進一步劃分為 4 KB 的塊,供 Kestrel 內(nèi)部使用。板塊必須大于 85 KB,以便在大對象堆上強制分配,以盡量防止 GC 重新定位這個陣列。然而,隨著新一代 GC 的引入,Pinned Object Heap(POH),在板塊上分配塊已經(jīng)沒有意義了。在預覽版 3 中,我們現(xiàn)在直接在 POH 上分配塊[7],降低了管理自己的內(nèi)存池所涉及的復雜性。這個變化應該可以更容易地執(zhí)行未來的改進,比如讓 Kestrel 使用的內(nèi)存池更容易收減。
11用于 WPF 和 Windows 窗體的 BlazorWebView 控件
對于 .NET 6,我們增加了對使用 .NET MAUI 和 Blazor 構(gòu)建跨平臺混合桌面應用程序的支持。混合應用程序是利用 Web 技術實現(xiàn)其功能的本地應用程序。例如,一個混合應用程序可能會使用一個嵌入式的 Web 視圖控件來渲染 Web UI。這意味著你可以使用 HTML 和 CSS 等 Web 技術編寫應用程序 UI,同時還可以使用本地設備的功能。我們將在即將發(fā)布的 .NET 6 預覽版中引入對使用 .NET MAUI 和 Blazor 構(gòu)建混合應用程序的支持。
在這個版本中,我們?yōu)?WPF 和 Windows Forms 應用程序引入了BlazorWebView控件,該控件可將 Blazor 功能嵌入到基于 .NET 6 的現(xiàn)有 Windows 桌面應用程序中。使用 Blazor 和混合方式,你可以將你的 UI 與 WPF 和 Windows Forms 解耦。這是一種對現(xiàn)有桌面應用程序進行現(xiàn)代化改造的好方法,可以將其帶到 .NET MAUI 上或在 Web 上使用。你可以使用 Blazor 對現(xiàn)有的 Windows Forms 和 WPF 應用程序進行現(xiàn)代化改造。
要使用新的BlazorWebView控件,你首先需要確保你已經(jīng)安裝了 WebView2[8]。
要將 Blazor 功能添加到現(xiàn)有的 Windows Forms 應用程序中,需要:
更新 Windows Forms 應用程序,使其 Target 為 .NET 6。
把應用程序項目文件中的 SDK 更新為 Microsoft.NET.Sdk.Razor。
添加Microsoft.AspNetCore.Components.WebView.WindowsForms包引用。
在項目中添加以下wwwroot/index.html文件,用實際的項目名稱替換{PROJECT NAME}:
<!DOCTYPE html> <html><head><meta?charset="utf-8" /><metaname="viewport"content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/><title>Blazor app</title><base?href="/" /><link?href="{PROJECT NAME}.styles.css"?rel="stylesheet" /><link?href="app.css"?rel="stylesheet" /></head><body><div?id="app"></div><div?id="blazor-error-ui">An unhandled error has occurred.<a?href=""?class="reload">Reload</a><a?class="dismiss">????</a></div><script?src="_framework/blazor.webview.js"></script></body> </html>在 wwwroot 文件夾中添加以下app.css文件,包含一些基本樣式:
html, body {font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; }.valid.modified:not([type='checkbox']) {outline: 1px solid #26b050; }.invalid {outline: 1px solid red; }.validation-message {color: red; }#blazor-error-ui {background: lightyellow;bottom: 0;box-shadow: 0 -1px?2px?rgba(0, 0, 0, 0.2);display: none;left: 0;padding: 0.6rem?1.25rem?0.7rem?1.25rem;position: fixed;width: 100%;z-index: 1000; }#blazor-error-ui?.dismiss {cursor: pointer;position: absolute;right: 0.75rem;top: 0.5rem; }對于 wwwroot 文件夾中的所有文件,將Copy to Output Directory屬性設置為Copy if newer。
在項目中添加一個 Blazor 根組件Counter.razor:
@using Microsoft.AspNetCore.Components.Web<h1>Counter</h1><p>The current count is: @currentCount</p> <button @onclick="IncrementCount">Count</button>@code {int currentCount = 0;void?IncrementCount(){currentCount++;} }將BlazorWebView控件添加到所需的表單中,以渲染 Blazor 根組件:
var serviceCollection = new ServiceCollection(); serviceCollection.AddBlazorWebView(); var blazor = new BlazorWebView() {Dock = DockStyle.Fill,HostPage = "wwwroot/index.html",Services = serviceCollection.BuildServiceProvider(), }; blazor.RootComponents.Add<Counter>("#app"); Controls.Add(blazor);運行該應用程序,查看BlazorWebView的運行情況。
要將 Blazor 功能添加到現(xiàn)有的 WPF 應用程序中,請按照上面列出的 Windows 窗體應用程序的相同步驟進行操作。另外:
為Microsoft.AspNetCore.Components.WebView.Wpf替換包引用。
在 XAML 中添加BlazorWebView控件:
<Window?x:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WpfApp1"xmlns:blazor="clr-namespace:Microsoft.AspNetCore.Components.WebView.Wpf;assembly=Microsoft.AspNetCore.Components.WebView.Wpf"mc:Ignorable="d"Title="MainWindow"?Height="450"?Width="800"><Grid><blazor:BlazorWebView?HostPage="wwwroot/index.html"?Services="{StaticResource services}"><blazor:BlazorWebView.RootComponents><blazor:RootComponent?Selector="#app"?ComponentType="{x:Type local:Counter}" /></blazor:BlazorWebView.RootComponents></blazor:BlazorWebView></Grid> </Window>將服務提供者設置為靜態(tài)資源:
var serviceCollection = new ServiceCollection(); serviceCollection.AddBlazorWebView(); Resources.Add("services", serviceCollection.BuildServiceProvider());為了解決 WPF 運行時構(gòu)建時找不到 Razor 組件類型的問題,在Counter.razor.cs中為組件添加一個空的局部類:
public?partial?class?Counter { }構(gòu)建并運行基于 Blazor 的 WPF 應用:
12提供反饋
我們希望你喜歡這個 .NET 6 預覽版中的 ASP.NET Core 部分。我們渴望聽到你對這個版本的體驗。請在 GitHub 上提交 Issue,讓我們知道你的想法。
謝謝你試用 ASP.NET Core!
文中鏈接:
https://dotnet.microsoft.com/download/dotnet/6.0 https://docs.microsoft.com/zh-cn/dotnet/core/compatibility/6.0#aspnet-core https://github.com/dotnet/aspnetcore/pull/30320 https://stackexchange.github.io/StackExchange.Redis/Profiling_v2.html https://docs.microsoft.com/visualstudio/debugger/supported-code-changes-csharp https://github.com/halter73/SignalR-Client-Cpp-Sample https://github.com/dotnet/aspnetcore/pull/30732 https://developer.microsoft.com/microsoft-edge/webview2/#download-p 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的.NET 6 Preview 3 中 ASP.NET Core 的更新和改进的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .Net5 WPF快速入门系列教程
- 下一篇: NET问答: 发布 asp.net co