共用方式為


武士刀計畫概述

作者: 霍華德·迪爾金

ASP.NET 框架已存在超過十年,該平台促成了無數網站與服務的開發。 隨著網頁應用程式開發策略的演進,該框架能夠隨著 ASP.NET MVC 和 ASP.NET Web API 等技術同步演進。 隨著網頁應用程式開發邁向雲端運算世界的下一個演進階段,Project Katana 為 ASP.NET 應用程式提供了底層元件組合,使其具備彈性、可攜性、輕量化,並提升效能——換句話說,Project Katana 雲端優化您的 ASP.NET 應用程式。

為什麼選擇武士刀——為什麼是現在?

無論討論的是開發者框架還是終端用戶產品,了解開發產品的背後動機都很重要——其中一部分也包括了解產品是為誰而創造。 ASP.NET 最初是為兩位客戶設計的。

第一批客戶是經典的 ASP 開發者。 當時,ASP 是用來建立動態、資料驅動網站與應用程式的主要技術之一,透過結合標記語言與伺服器端腳本。 ASP 執行環境提供伺服器端腳本一組物件,抽象底層 HTTP 協定與網頁伺服器的核心面向,並提供存取額外服務,如會話與應用狀態管理、快取等。雖然功能強大,但經典的 ASP 應用程式隨著規模與複雜度的增加,管理變得具有挑戰性。 這主要是因為腳本環境缺乏結構,加上程式碼與標記交錯導致的程式碼重複。 為了發揮經典 ASP 的優勢並解決其部分挑戰,ASP.NET 利用 .NET Framework 物件導向語言所提供的程式碼組織,同時保留了經典 ASP 開發者習慣的伺服器端程式設計模式。

ASP.NET 的第二類目標客戶是 Windows 商業應用程式開發者。 與習慣撰寫 HTML 標記及產生更多 HTML 標記程式碼的傳統 ASP 開發者不同,WinForms 開發者(如同之前的 VB6 開發者)習慣於設計時的體驗,包含畫布與豐富的使用者介面控制項。 ASP.NET 的第一個版本(又稱「網頁表單」)提供了類似的設計體驗,並結合了使用者介面元件的伺服器端事件模型,以及一套基礎設施功能(如 ViewState),以打造客戶端與伺服器端程式設計間無縫的開發體驗。 Web Forms 實際上將 Web 的無狀態特性隱藏在 WinForms 開發者熟悉的有狀態事件模型之下。

歷史模型所提出的挑戰

最終結果是一個成熟且功能豐富的執行環境與開發者程式設計模型。 然而,正因為功能豐富,卻也帶來了幾個顯著的挑戰。 首先,該框架是 單一結構,邏輯上不同的功能單元緊密結合在同一 System.Web.dll 組合中(例如,Web 表單框架中的核心 HTTP 物件)。 其次,ASP.NET 被納入更大的 .NET 框架,這意味著 版本之間的間隔大約是數年。 這使得 ASP.NET 難以跟上快速演進的網頁開發變化。 最後,System.Web.dll 本身以幾種方式與特定的網頁主機選項——網際網路資訊服務(Internet Information Services,IIS)結合。

演進步驟:ASP.NET MVC 與 ASP.NET Web API

網頁開發領域也發生了許多變革! 網頁應用程式越來越多地被開發為一系列小型、聚焦的元件,而非大型框架。 組件數量及其釋放頻率正以越來越快的速度增加。 顯然,要跟上網路的腳步,框架必須變得更小、更解耦且更聚焦,而非更大且功能更豐富,因此 ASP.NET 團隊採取了多項演進步驟,使 ASP.NET 成為一個可插拔的網頁元件家族,而非單一框架

早期的變革之一是知名的模型-視圖-控制器(MVC)設計模式因 Ruby on Rails 等網頁開發框架而日益流行。 這種網頁應用建置方式讓開發者能更好地掌控應用程式的標記,同時保留標記與業務邏輯的分離,這也是 ASP.NET 最初的賣點之一。 為了滿足此類型的網頁應用程式開發需求,Microsoft 抓住機會為未來做準備, 獨立開發了 ASP.NET MVC (且未將其納入 .NET Framework 中)。 ASP.NET MVC 以獨立下載形式發行。 這讓工程團隊能比以往更頻繁地提供更新。

網頁應用開發的另一大轉變是從動態伺服器生成的網頁轉向靜態初始標記,頁面由客戶端腳本 透過 AJAX 請求與後端 Web API 通訊產生動態區段。 這種架構轉變促進了 Web API 的興起,以及 ASP.NET Web API 框架的發展。 如同 ASP.NET MVC,ASP.NET Web API 的發布提供了另一個機會,讓 ASP.NET 進一步演進成為更模組化的框架。 工程團隊把握機會, 打造 ASP.NET Web API,使其不依賴 System.Web.dll中任何核心框架類型 。 這 ASP.NET 促成了兩件事:首先,讓 Web API 能夠完全自成一格地演進(而且因為它是透過 NuGet 交付,所以能持續快速迭代)。 其次,由於沒有外部相依 System.Web.dll,因此也沒有依賴於 IIS,ASP.NET Web API 包含在自訂主機上執行的功能(例如主控台應用程式、Windows 服務等)。

未來:靈活的框架

透過將框架元件彼此解耦,然後在 NuGet 上釋出,框架現在能 更獨立且更快地迭代。 此外,Web API 自架能力的強大與彈性,對想要小型 輕量主機 的開發者極具吸引力。 事實上,它非常吸引人,以致其他框架也想要這項功能,這也帶來了新的挑戰:每個框架都運行在自己的主機程序和自己的基址上,且需要獨立管理(啟動、停止等)。 現代網頁應用程式通常支援靜態檔案服務、動態頁面產生、Web API,以及近年來的即時/推播通知。 期望這些服務各自獨立運作與管理,實在不切實際。

當時需要的是一個單一的主機抽象,讓開發者能從各種不同的元件和框架中組合應用程式,然後在支援的主機上執行該應用程式。

.NET 開放網頁介面(OWIN)

受到 Rack 在 Ruby 社群中帶來的好處啟發,.NET 社群的幾位成員著手創造網頁伺服器與框架元件之間的抽象。 OWIN 抽象的兩個設計目標是簡單,以及對其他框架類型的依賴最少。 這兩個目標有助於確保:

  • 新元件可以更容易地進行開發和使用。
  • 應用程式可以更容易在主機之間,甚至整個平台或作業系統之間移植。

由此產生的抽象包含兩個核心元素。 第一個是環境字典。 此資料結構負責儲存處理 HTTP 請求與回應所需的所有狀態,以及任何相關的伺服器狀態。 環境字典的定義如下:

IDictionary<string, object>

OWIN 相容的網頁伺服器負責將 HTTP 請求與回應所需的資料(如主體串流與標頭集合)填充環境字典。 接著,應用程式或框架元件負責為字典填入或更新額外值,並寫入回應主體串流。

除了指定環境字典的類型外,OWIN 規範還定義了核心字典的鍵值對清單。 例如,下表顯示 HTTP 請求所需的字典金鑰:

鍵名稱 價值說明
"owin.RequestBody" 有一個包含請求主體的串流(如果有的話)。 如果沒有請求主體,Stream.Null 可以用作佔位符。 請參見 請求正文
"owin.RequestHeaders" IDictionary<string, string[]> 組請求標頭。 請參閱 頁頭
"owin.RequestMethod" string A 包含請求的 HTTP 請求方法(例如, "GET""POST")。
"owin.RequestPath" 一個包含請求路徑的 string。 路徑必須相對於應用程式代理的「根」節點;參見 路徑
"owin.RequestPathBase" A string 包含對應於應用程式代理「根」的請求路徑部分;詳見路徑。
"owin.RequestProtocol" 包含協定名稱與版本的 A string (例如 "HTTP/1.0""HTTP/1.1")。
"owin.RequestQueryString" A string 包含 HTTP 請求 URI 中的查詢字串元件,但不包括開頭的「?」(例如,"foo=bar&baz=quux")。 該值可能是空字串。
"owin.RequestScheme" string A 包含用於請求的 URI 方案(例如 "http", , "https");參見 URI 方案

OWIN 的第二個關鍵元素是應用程式代理。 這是一個函式簽章,作為 OWIN 應用程式中所有元件之間的主要介面。 申請代表的定義如下:

Func<IDictionary<string, object>, Task>;

應用程式代理就是 Func 代理型態的實作,函式接受環境字典作為輸入並回傳任務。 此設計對開發者有多項影響:

  • 撰寫 OWIN 元件所需的型別依賴性非常少。 這大大提升了 OWIN 對開發者的可及性。
  • 非同步設計使抽象在處理計算資源時更有效率,尤其是在較依賴 I/O 的操作中。
  • 由於應用程式代理是執行的原子單元,且環境字典作為代理上的參數,OWIN 元件可以輕鬆串連起來,建立複雜的 HTTP 處理管線。

從實作角度來看,OWIN 是一個規範(http://owin.org/html/owin.html)。 它的目標不是成為下一個 Web 框架,而是規範 Web 框架與 Web 伺服器之間的互動方式。

如果你有研究過 OWINKatana,可能也注意到 Owin NuGet 套件 和 Owin.dll。 此函式庫包含單一介面 [IAppBuilder]/dotnet/api/microsoft.aspnetcore.builder.iapplicationbuilder),正式化並編碼 OWIN 規範第 4 節 所述的啟動序列。 雖然建置 OWIN 伺服器並非必要條件,但 [IAppBuilder]/dotnet/api/microsoft.aspnetcore.builder.iapplicationbuilder) 介面提供了一個具體的參考點,Katana 專案元件會使用。

武士刀計畫

OWIN 規範與 Owin.dll為社群擁有且由社群運營的開源專案,Katana 專案則代表由 Microsoft 建置並發布的 OWIN 元件集合,雖然仍是開源。 這些元件包括基礎設施元件,如主機與伺服器,以及功能元件,如認證元件及綁定 SignalRASP.NET Web API 等框架。 該專案有以下三個高層目標:

  • 可攜式 ——元件應能在新元件出現時輕鬆替換。 這包括所有類型的元件,從框架到伺服器和主機。 這個目標的意涵是,第三方框架可以無縫地在 Microsoft 伺服器上執行,而 Microsoft 框架則有可能在第三方伺服器和主機上運行。
  • 模組化/彈性——與許多預設開啟的眾多功能框架不同,Katana 專案的元件應該小巧且聚焦,讓應用程式開發者自行決定在應用中使用哪些元件。
  • 輕量級/效能高/可擴展 性——透過將傳統框架拆解為一組由應用程式開發者明確添加的小型、聚焦元件,最終的 Katana 應用程式能消耗較少的運算資源,因此能承受比其他類型的伺服器和框架更高的負載。 隨著應用程式需求需要底層基礎設施提供更多功能,這些功能可以加入 OWIN 流程,但這應該由應用程式開發者明確決定。 此外,低階元件的可替換性意味著當這些元件可用時,能無縫引入新的高效能伺服器,以提升 OWIN 應用程式的效能,同時不會破壞這些應用程式。

開始使用 Katana 元件

Node.js 框架剛推出時,立刻吸引大家注意的一點是,網頁伺服器的撰寫與運行非常簡單。 如果以 Node.js為基礎來定義 Katana 的目標,可以總結為:Katana 帶來了許多 Node.js (及類似框架)的優點,卻不必強迫開發者拋棄她對 ASP.NET 網頁應用開發的所有知識。 要這句話才算成立,開始使用 Katana 專案的流程本質上也應該要如同 Node.js 一樣簡單。

建立「Hello World!」

JavaScript 與 .NET 開發的一個顯著差異是編譯器的存在或缺失。 因此,簡單的 Katana 伺服器起點是 Visual Studio 專案。 不過,我們可以從最基本的專案類型開始:Empty ASP.NET Web Application。

ASP.Net 專案 - WebApplication1 選單的截圖,說明如何啟動視窗窗格以建立「Hello World」專案。會顯示一個視窗,裡面有不同的範本可供選擇,以及新增核心參考和單元測試的選項。

接著,我們將將 Microsoft.Owin.Host.SystemWeb NuGet 套件安裝到專案中。 此套件提供一台在 ASP.NET 請求管線中運行的 OWIN 伺服器。 它可以在 NuGet 畫廊 中找到,並可透過 Visual Studio 套件管理器對話框或套件管理主控台的以下指令安裝:

install-package Microsoft.Owin.Host.SystemWeb

安裝 Microsoft.Owin.Host.SystemWeb 套件時,會額外安裝幾個相依性套件。 其中一個相依關係是 Microsoft.Owin函式庫,提供多種輔助工具類型與方法以開發 OWIN 應用程式。 我們可以利用這些類型快速撰寫以下「hello world」伺服器。

public class Startup
{
   public void Configuration(IAppBuilder app)
   {
      app.Run(context =>
      {
         context.Response.ContentType = "text/plain";
         return context.Response.WriteAsync("Hello World!");
      });
   }
}

這個非常簡單的網頁伺服器現在可以使用 Visual Studio 的 F5 指令執行,並完整支援除錯。

交換主機

預設情況下,前述的「hello world」範例運行於 ASP.NET 請求管線,該管線在 IIS 脈絡下使用 System.Web。 這本身就能帶來極大價值,因為它使我們能利用 OWIN 管線的彈性與組合性,同時具備 IIS 的管理能力與整體成熟度。 然而,有時 IIS 提供的優勢並非必需,且希望擁有更小、更輕量的主機。 那麼,要在 IIS 和 System.Web 之外運行我們的簡單網頁伺服器,需要什麼?

為了說明可攜性目標,從網頁伺服器主機轉移到命令列主機,只需將新的伺服器與主機依賴加入專案的輸出資料夾,然後啟動主機即可。 在這個例子中,我們將將網頁伺服器架設在一個名為 OwinHost.exe Katana 的主機上,並使用 Katana HttpListener 伺服器。 與其他 Katana 元件類似,這些元件將透過以下指令從 NuGet 取得:

install-package OwinHost

從命令列,我們可以導航到專案根目錄,然後執行 OwinHost.exe(該工具安裝在相應 NuGet 套件的 tools 資料夾中)。 預設情況下, OwinHost.exe 會設定尋找基於 HttpListener 的伺服器,因此不需要額外的設定。 在網頁瀏覽器中導航至 http://localhost:5000/ 時,您將會看到應用程式正在控制台中運行。

開發者指令程式與瀏覽器視窗的截圖,展示了命令列輸入指令與瀏覽器中「Hello World」專案的比較。

Katana 架構

Katana 元件架構將應用程式劃分為四個邏輯層,如下所示:主機、伺服器、中介軟體與應用程式。 元件架構的設計使這些層的實作能輕易替換,且在許多情況下無需重新編譯應用程式。

架構層圖顯示四條橫線,顯示應用程式架構被劃分為的邏輯層。

Host

主持人負責:

  • 管理底層流程。

  • 協調流程,選擇伺服器並建構 OWIN 流程,透過該流程處理請求。

    目前,Katana 應用主要有三種主機方案:

IIS/ASP.NET:使用標準的 HttpModule 與 HttpHandler 類型,OWIN 管線可作為 ASP.NET 請求流程的一部分在 IIS 上執行。 ASP.NET 主機支援是透過將 Microsoft.AspNet.Host.SystemWeb NuGet 套件安裝到網頁應用程式專案中來啟用的。 此外,由於 IIS 同時擔任主機與伺服器的角色,OWIN 伺服器與主機的區別在此 NuGet 套件中被混淆,意即若使用 SystemWeb 主機,開發者無法以替代伺服器實作。

自訂主機:Katana 元件套件讓開發者能夠以自己的自訂流程來架設應用程式,無論是主控台應用程式、Windows 服務等。此能力與 Web API 提供的自架能力相似。 以下範例展示了自訂的 Web API 程式碼主機:

static void Main()
{
    var baseAddress = new Uri("http://localhost:5000");

    var config = new HttpSelfHostConfiguration(baseAddress);
    config.Routes.MapHttpRoute("default", "{controller}");
       
    using (var svr = new HttpSelfHostServer(config))
    {
        svr.OpenAsync().Wait();
        Console.WriteLine("Press Enter to quit.");
        Console.ReadLine();
    }
}

Katana 應用程式的自主機設定類似:

static void Main(string[] args)
{
    const string baseUrl = "http://localhost:5000/";

    using (WebApplication.Start<Startup>(new StartOptions { Url = baseUrl })) 
    {
        Console.WriteLine("Press Enter to quit.");
        Console.ReadKey();
    }
}

Web API 與 Katana 自架範例的一個顯著差異是,Katana 自家主機範例缺少 Web API 設定程式碼。 為了同時實現可攜性與組合性,Katana 將啟動伺服器的程式碼與配置請求處理管線的程式碼分開。 設定 Web API 的程式碼包含在 Startup 類別中,該類別在 WebApplication.Start 中也指定為型別參數。

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var config = new HttpConfiguration();
        config.Routes.MapHttpRoute("default", "{controller}");
        app.UseWebApi(config);
    }
}

新創課程將在文章後面更詳細討論。 然而,啟動 Katana 自我託管程序所需的程式碼,與你目前在 ASP.NET Web API 自我託管應用程式中使用的程式碼驚人地相似。

OwinHost.exe:雖然有些人想寫自訂程序來執行 Katana 網頁應用程式,但許多人寧願直接啟動一個預先建構的執行檔,啟動伺服器並執行應用程式。 在此情境下,Katana 的元件套件包含 OwinHost.exe。 當從專案根目錄執行時,這個執行檔會啟動伺服器(預設使用 HttpListener 伺服器),並使用慣例尋找並執行使用者的啟動類別。 為了更細緻的控制,執行檔提供多個額外的命令列參數。

開發者指令提示字元的截圖,顯示命令提示字元在伺服器上執行應用程式時的程式碼範例。

伺服器

主機負責啟動並維護應用程式運行的程序,伺服器則負責開啟網路接字、監聽請求,並將請求透過使用者指定的 OWIN 元件管線傳送(如你可能已注意到,該管線在應用程式開發者的啟動類別中被指定)。 目前,Katana 專案包含兩種伺服器實作:

  • Microsoft.Owin.Host.SystemWeb:如前所述,IIS 與 ASP.NET 管線協同,同時擔任主機與伺服器。 因此,選擇此主機選項時,IIS 同時管理主機層級的事務,如程序啟動,並監聽 HTTP 請求。 對於 ASP.NET 網頁應用程式,接著會將請求送入 ASP.NET 管線。 Katana SystemWeb 主機會註冊一個 ASP.NET HttpModule 和 HttpHandler,攔截透過 HTTP 管線的請求,並將其發送到使用者指定的 OWIN 管線。
  • Microsoft.Owin.Host.HttpListener:顧名思義,這台 Katana 伺服器使用 .NET Framework 的 HttpListener 類別來開啟 socket 並將請求傳送到開發者指定的 OWIN 管線。 目前這是 Katana 自我託管 API 與 OwinHost.exe 的預設伺服器選項。

中介軟體/框架

如前所述,當伺服器接受客戶端的請求時,需負責將該請求通過由開發者啟動程式碼指定的 OWIN 元件管線傳遞。 這些管線元件稱為中介軟體。
在非常基本的層面上,OWIN 中介軟體元件只需實作 OWIN 應用程式代理,使其可呼叫。

Func<IDictionary<string, object>, Task>

然而,為了簡化中介軟體元件的開發與組合,Katana 支援少數幾種中介軟體元件的慣例與輔助類型。 其中最常見的是類別 OwinMiddleware 。 使用此類別建置的自訂中介軟體元件會類似以下內容:

public class LoggerMiddleware : OwinMiddleware
{
    private readonly ILog _logger;
 
    public LoggerMiddleware(OwinMiddleware next, ILog logger) : base(next)
    {
        _logger = logger;
    }
 
    public override async Task Invoke(IOwinContext context)
    {
        _logger.LogInfo("Middleware begin");
        await this.Next.Invoke(context);
        _logger.LogInfo("Middleware end");
    }
}

此類別源自 OwinMiddleware,實作一個建構子,接受管線中下一個中介軟體的實例作為參數之一,然後傳遞給基底建構子。 用於配置中介軟體的其他參數也會在下一個中介軟體參數之後宣告為建構參數。

在運行時,中介軟體會透過覆寫 Invoke 方法執行。 此方法接受一個OwinContext型別的單一參數。 此上下文物件由 Microsoft.Owin 前述的 NuGet 套件提供,並提供強型別存取請求、回應與環境字典,並附帶幾種額外的輔助工具類型。

中介軟體類別可輕易地在應用程式啟動程式碼中加入 OWIN 管線,方法如下:

public class Startup
{
   public void Configuration(IAppBuilder app)
   {
      app.Use<LoggerMiddleware>(new TraceLogger());

   }
}

由於 Katana 基礎架構只是建立一條 OWIN 中介軟體元件的管線,且元件只需支援應用程式代理方才能參與流程,中介軟體元件的複雜度可以從簡單的記錄器到像 ASP.NET、Web API 或 SignalR 這樣的整個框架不等。 例如,將 ASP.NET Web API 加入先前的 OWIN 管線,需要新增以下啟動程式碼:

public class Startup
{
   public void Configuration(IAppBuilder app)
   {
      app.Use<LoggerMiddleware>(new TraceLogger());

      var config = new HttpConfiguration();
      // configure Web API 
      app.UseWebApi(config);

      // additional middleware registrations            
   }
}

Katana 基礎架構會根據中介軟體元件在配置方法中加入 IAppBuilder 物件的順序,建立中介軟體元件的管線。 因此,在我們的例子中,LoggerMiddleware 可以處理所有流經管線的請求,無論這些請求最終如何處理。 這使得中介軟體元件(例如認證元件)能夠處理包含多個元件與框架(例如 ASP.NET Web API、SignalR 及靜態檔案伺服器)的管道請求,實現強大的情境。

應用程式

如前述範例所示,OWIN 與 Katana 專案不應被視為新的應用程式設計模型,而應被視為一種抽象,旨在將應用程式設計模型與框架與伺服器及主機基礎設施解耦。 例如,在建置 Web API 應用程式時,開發者框架仍會持續使用 ASP.NET Web API 框架,無論應用程式是否在使用 Katana 專案元件的 OWIN 管線中執行。 唯一能讓應用程式開發者看到 OWIN 相關程式碼的地方,就是應用程式啟動程式碼,也就是開發者撰寫 OWIN 管線的地方。 在啟動程式碼中,開發者會註冊一系列 UseXx 語法,通常每個語法對應一個處理進來的請求的中介軟體元件。 這種體驗將與目前 System.Web 世界中註冊 HTTP 模組產生相同效果。 通常,較大型的框架中介軟體,如 ASP.NET Web API 或 SignalR ,會在管線末端註冊。 跨領域中介軟體元件,如認證或快取元件,通常會在管線開始時註冊,以便處理後續註冊的所有框架與元件的請求。 中介軟體元件彼此分離,並與底層基礎設施元件分離,使元件能以不同速度演進,同時確保整體系統穩定。

元件 – NuGet 套件

如同許多現有函式庫與框架,Katana 專案元件以一組 NuGet 套件形式交付。 在即將推出的 2.0 版本中,Katana 套件的相依關係圖如下。 (點擊圖片可放大查看。)

元件示意圖 - NuGet 套件階層結構。這張圖片展示了框架連接專案元件的函式庫樹狀結構,並透過一組 NuGets 交付。

Katana 專案中的幾乎每個套件都直接或間接依賴 Owin 套件。 你可能記得這是包含 IAppBuilder 介面的套件,該介面提供了 OWIN 規範第 4 節中描述的應用程式啟動序列的具體實作。 此外,許多套件依賴 Microsoft.Owin,該軟體提供一組輔助型態以處理 HTTP 請求與回應。 套件的其餘部分可分為主機基礎設施套件(伺服器或主機)或中介軟體。 Katana 專案外部的套件與相依性以橘色顯示。

Katana 2.0 的主機基礎設施包含基於 SystemWeb 與 HttpListener 的伺服器、用於使用 OwinHost.exe執行 OWIN 應用程式的 OwinHost 套件,以及用於自訂主機(例如主控台應用程式、Windows 服務等)自架 OWIN 應用程式的 Microsoft.Owin.Hosting 套件。

對於 Katana 2.0,中介軟體元件主要著重於提供不同的認證方式。 還提供一個額外的診斷中介軟體元件,能夠支援啟動和錯誤頁面的功能。 隨著 OWIN 發展成事實上的託管抽象化,Microsoft 及第三方開發的中介軟體元件生態系也將持續增加。

結論

從一開始,Katana 專案的目標並非創造並強迫開發者學習另一個網頁框架。 相反地,目標是創造一個抽象化,讓 .NET 網頁應用程式開發者比以往更多選擇。 Katana 專案透過將典型網頁應用堆疊的邏輯層拆解為一組可替換的元件,使整個堆疊中的元件能以符合該元件合理速度的改進。 Katana 透過圍繞簡單的 OWIN 抽象構建所有元件,使框架及其上建置的應用程式能夠跨越多種不同伺服器與主機進行移植。 Katana 讓開發者掌控整個堆疊,確保開發者能做出最終決定,他們的網頁架構應該是輕量還是功能豐富。

欲知更多有關 Katana 的資訊

致謝