天天看點

.NET 6 Preview 3 中 ASP.NET Core 的更新和改進

.NET 6 預覽版 3 現已推出,其中包括許多對新的 ASP.NET Core 改進。以下是本次預覽版的新内容......

原文:bit.ly/2Qb56NP

作者:Daniel Roth

譯者:精緻碼農-王亮

.NET 6 預覽版 3 現已推出,其中包括許多對新的 ASP.NET Core 改進。以下是本次預覽版的新内容:

  • 更小的 SignalR、Blazor Server、MessagePack 腳本檔案
  • 啟用 Redis 分析會話
  • HTTP/3 端點 TLS 配置
  • 初步 .NET 熱重載支援
  • Razor 編譯器不再生成單獨的視圖 Assembly
  • IIS 中的淺拷貝支援
  • 适用于 SignalR C++ 用戶端的 Vcpkg 端口
  • 減少閑置 TLS 連接配接的記憶體占用量
  • 從 SlabMemoryPool 中移除闆塊
  • 用于 WPF 和 Windows 窗體的 BlazorWebView 控件

開始

要在.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 的最新預覽版。

更新現有項目

要将現有的 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]。

更小的腳本檔案

得益于 Ben Adams 的社群貢獻,SignalR、MessagePack 和 Blazor Server 腳本現在明顯變小了,下載下傳體積減少,浏覽器解析和編譯 JavaScript 的次數減少,啟動速度加快。

這項工作帶來的下載下傳體積減少是非常驚人的:

Library Before After %↓ .br
signalr.min.js 130 KB 39 KB 70% 10 KB
blazor.server.js 212 KB 116 KB 45% 28 KB

現在你也隻需要為 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] 中找到更多關于這些變化的細節。

我們接受了 Gabriel Lucaci 的社群貢獻,在此預覽版中使用

Microsoft.Extensions.Caching.StackExchangeRedis

啟用 Redis 分析會話。關于 Redis 分析的更多細節,請參見官方文檔[4]。該 API 的使用方法如下:

services.AddStackExchangeRedisCache(options =>
{
    options.ProfilingSession = () => new ProfilingSession();
})
           

HTTP/3 與現有的 HTTP 協定相比具有許多優勢,包括更快的連接配接設定,以及在低品質網絡上的性能改進。

在此預覽版中,新增了使用

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();
        });
    });
})
           

現在,使用

dotnet watch

的 ASP.NET Core 和 Blazor 項目可以獲得對 .NET 熱重載的早期支援。.NET 熱重載可以在不重新啟動應用程式和不丢失應用程式狀态的情況下将代碼更改應用到你正在運作的應用程式中。

要在現有的基于 .NET 6 的 ASP.NET Core 項目中試用熱重載,請将

"hotReloadProfile": "aspnetcore"

屬性添加到你的

launchSettings.json

檔案中。對于 Blazor WebAssembly 項目,使用

"blazorwasm"

熱重載配置檔案。

使用

dotnet watch

運作項目。下面的輸出表明熱重載已經啟用:

watch : Hot reload enabled. For a list of supported edits, see https://aka.ms/dotnet/hot-reload. Press "Ctrl + R" to restart.
           

在任何時候你想強制應用程式重新建構和重新開機,你可以在控制台輸入

Ctrl+R

來實作。

現在你可以開始對你的代碼進行編輯了。當你儲存代碼更改時,相應的更改幾乎會在瞬間自動熱重載到運作中的應用程式中。運作中的應用程式中的任何狀态都會被保留。

你也可以對你的 CSS 檔案進行熱重載更改,而不需要重新整理浏覽器:

有一些代碼更改不支援 .NET 執重載。你可以在文檔[5]中找到支援的代碼編輯清單。在 Blazor WebAssembly 中,目前隻支援方法體替換。我們正在努力擴充 .NET 6 中支援的編輯集。當

dotnet watch

檢測到無法使用熱重載應用的更改時,它就會退回重新建構和重新啟動應用程式。

這隻是 .NET 6 中熱重載支援的開始。桌面和移動應用程式的熱重載支援将很快在即将到來的預覽版中提供,以及在 Visual Studio 中內建熱重載。

我們在 IIS 的 ASP.NET Core 子產品中添加了一個新功能,以增加對淺拷貝應用程式程式集的支援。目前,.NET 在 Windows 上運作時鎖定了應用程式的二進制檔案,使得在應用程式仍在運作時無法替換二進制檔案。雖然我們的建議仍然是使用應用程式脫機檔案,但我們認識到在某些情況下(例如 FTP 部署)不可能這樣做。

在這種情況下,你可以通過自定義 ASP.NET Core 子產品處理程式設定來啟用淺拷貝。在大多數情況下,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 section.
  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 站點運作時擴充。

.NET 6 Preview 3 中 ASP.NET Core 的更新和改進

Vcpkg 是一個跨平台的 C 和 C++庫的指令行包管理器。最近,我們為 vcpkg 添加了一個移植版本,為 SignalR C++ 用戶端添加了 CMake 本地支援(也适用于 MSBuild 項目)。

你可以用下面的代碼來添加 SignalR 用戶端到你的 CMake 項目中(假設你已經包含了 vcpkg 工具鍊檔案)。

find_package(microsoft-signalr CONFIG REQUIRED)
link_libraries(microsoft-signalr::microsoft-signalr)
           

在這之後,SignalR C++ 用戶端就可以被

#include

并用于你的項目中,而不需要任何額外的配置。這個倉庫[6]是一個完整的使用 SignalR C++ 用戶端的 C++ 應用程式的例子。

對于隻偶爾來回發送資料的 TLS 長連接配接,我們已經大大減少了 .NET 6 中 ASP.NET Core 應用程式的記憶體占用。這應該有助于提高 WebSocket 伺服器等場景的可擴充性。這得益于

System.IO.Pipelines

SslStream

Kestrel

的衆多改進。讓我們來看看促成這一方案的一些改進。

縮減 System.IO.Pipelines.Pipe 大小

對于我們建立的每一個連接配接,我們都會在 Kestrel 中配置設定兩個管道:一個是從傳輸層到應用的請求,另一個是從應用層到傳輸的響應。通過将

System.IO.Pipelines.Pipe

的大小從 368 位元組縮減到 264 位元組(約 28.2%),我們為每個連接配接節省了 208 位元組(每個 Pipe 節省 104 位元組)。

SocketSender 池

SocketSender 對象在運作時約為 350 位元組。與其為每個連接配接配置設定一個新的 SocketSender 對象,我們可以将它們集中起來,因為發送通常非常快,我們可以減少每個連接配接的開銷。現在,我們不再為每個連接配接配置設定 350 位元組,而是隻為每個 IOQueue 配置設定 350 位元組(每個隊列一個,以避免争用)。在擁有 5000 個空閑連接配接的 WebSocket 伺服器中,我們從配置設定約 1.75 MB(350 位元組*5000)到現在隻配置設定約 2.8kb(350 位元組*8)給 SocketSender 對象。

SslStream 零位元組讀取

無緩沖讀取是我們已經在 ASP.NET Core 中采用的一種技術,以避免在套接字上沒有可用資料時從記憶體池中租用記憶體。在這一變化之前,我們的 WebSocket 伺服器有 5000 個空閑連接配接,在沒有 TLS 的情況下需要約 200 MB,而在有 TLS 的情況下需要約 800 MB。其中一些配置設定(每個連接配接 4k)是由于 Kestrel 在等待

SslStream

上的讀取完成時必須保持

ArrayPool

緩沖區。鑒于這些連接配接是空閑的,沒有一個讀取完成并将其緩沖區傳回給

ArrayPool

,迫使

ArrayPool

配置設定更多的記憶體。剩餘的配置設定都在

SslStream

本身。4k 緩沖區用于 TLS 握手,32k 緩沖區用于正常讀取。在預覽版 3 中,當使用者在

SslStream

上執行零位元組讀取,而它又沒有可用的資料時,

SslStream

會在内部對底層的封裝流執行零位元組讀取。在最好的情況下(空閑連接配接),這些變化導緻每個連接配接節省了 40 Kb,同時仍然允許消費者(Kestrel)在資料可用時得到通知,而無需保留任何未使用的緩沖區。

PipeReader 零位元組讀取

一旦

SslStream

支援無緩沖區讀取,我們就向

StreamPipeReader

(将

Stream

适配成

PipeReader

的内部類型)添加了執行零位元組讀取的選項。在 Kestrel 中,我們使用

StreamPipeReader

将底層的

SslStream

PipeReader

,有必要在

PipeReader

上暴露這些零位元組讀取語義。

現在,你可以使用以下 API 建立一個

PipeReader

,支援在任何支援零位元組讀取語義的

Stream

上進行零位元組讀取(例如

SslStream

NetworkStream

等)。

var reader = PipeReader.Create(stream, new StreamPipeReaderOptions(useZeroByteReads: true));
           

為了減少堆的碎片,Kestrel 采用了一種技術,它配置設定了 128 KB 的記憶體闆塊作為其記憶體池的一部分。然後,這些闆塊被進一步劃分為 4 KB 的塊,供 Kestrel 内部使用。闆塊必須大于 85 KB,以便在大對象堆上強制配置設定,以盡量防止 GC 重新定位這個陣列。然而,随着新一代 GC 的引入,Pinned Object Heap(POH),在闆塊上配置設定塊已經沒有意義了。在預覽版 3 中,我們現在直接在 POH 上配置設定塊[7],降低了管理自己的記憶體池所涉及的複雜性。這個變化應該可以更容易地執行未來的改進,比如讓 Kestrel 使用的記憶體池更容易收減。

對于 .NET 6,我們增加了對使用 .NET MAUI 和 Blazor 建構跨平台混合桌面應用程式的支援。混合應用程式是利用 Web 技術實作其功能的本地應用程式。例如,一個混合應用程式可能會使用一個嵌入式的 Web 視圖控件來渲染 Web UI。這意味着你可以使用 HTML 和 CSS 等 Web 技術編寫應用程式 UI,同時還可以使用本地裝置的功能。我們将在即将釋出的 .NET 6 預覽版中引入對使用 .NET MAUI 和 Blazor 建構混合應用程式的支援。

在這個版本中,我們為 WPF 和 Windows Forms 應用程式引入了

BlazorWebView

控件,該控件可将 Blazor 功能嵌入到基于 .NET 6 的現有 Windows 桌面應用程式中。使用 Blazor 和混合方式,你可以将你的 UI 與 WPF 和 Windows Forms 解耦。這是一種對現有桌面應用程式進行現代化改造的好方法,可以将其帶到 .NET MAUI 上或在 Web 上使用。你可以使用 Blazor 對現有的 Windows Forms 和 WPF 應用程式進行現代化改造。

要使用新的

BlazorWebView

控件,你首先需要確定你已經安裝了 WebView2[8]。

要将 Blazor 功能添加到現有的 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" />
        <meta
          name="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

    的運作情況。
    .NET 6 Preview 3 中 ASP.NET Core 的更新和改進

要将 Blazor 功能添加到現有的 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>
               
  • 将服務提供者設定為靜态資源:
    var serviceCollection = new ServiceCollection();
    serviceCollection.AddBlazorWebView();
    Resources.Add("services", serviceCollection.BuildServiceProvider());
               
  • 為了解決 WPF 運作時建構時找不到 Razor 元件類型的問題,在

    Counter.razor.cs

    中為元件添加一個空的局部類:
    public partial class Counter { }
               
  • 建構并運作基于 Blazor 的 WPF 應用:
    .NET 6 Preview 3 中 ASP.NET Core 的更新和改進

提供回報

我們希望你喜歡這個 .NET 6 預覽版中的 ASP.NET Core 部分。我們渴望聽到你對這個版本的體驗。請在 GitHub 上送出 Issue,讓我們知道你的想法。

謝謝你試用 ASP.NET Core!

作者:精緻碼農-王亮

出處:http://cnblogs.com/willick

聯系:[email protected]

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。如有問題或建議,請多多賜教,非常感謝。