本文章是由機器翻譯。

ASP.NET

開始著手 Katana 專案

Howard Dierking (HD)

早在 2002 年首次推出ASP.NET,當時間是不同的。互聯網在仍然相對嬰兒狀態,與大約 5 億 6900 萬 46 分鐘一天平均消費約 300 萬的 Web 網站上的使用者。採取只是 10 年後這些相同測量揭示大約 4 個小時,每日平均支出 5 億 5500 萬的 Web 網站上的 22 億 7000 萬使用者的互聯網 (見 bit.ly/MY7GzO)。

顯然,這種增長的刺激的基本框架、 工具、 和他們使用生成並運行 Web 應用程式的運行時應用程式開發人員需要相應變化。現代的 Web 應用程式需要能夠快速地演化,採取許多不同的元件和框架的優勢 — — 他們需要占地面積小,雲的大規模運行時中高效地運行。

確保ASP.NET可以滿足這些當前和未來的需求,是武士刀專案背後的核心動機。

武士刀是什麼?

埋下了種子的武士刀專案是實際上非微軟與調用打開 Web 除開放源碼專案­臉為.NET (浩然),一個規範,它定義了 Web 服務器和應用程式元件之間的交互 (請參閱 owin.org)。規範的目標是鼓勵微軟基於.NET 框架的 Web 服務器和應用程式元件的一個廣泛和充滿活力的生態系統,因為它減少了伺服器和應用程式的一小的類型和單個函數簽名被稱為應用程式委託或 AppFunc 之間的所有交互:

using AppFunc = Func<IDictionary<string, object>, Task>;

浩然基於應用程式中的每個元件提供到伺服器應用程式委託。元件然後被連結在一起入到其中的浩然基於伺服器推送請求管道。為了有效地利用資源,在管道中的所有元件應該都是非同步而這反映在返回任務物件的應用程式委託。

所有國家,包括應用程式狀態、 請求的狀態、 伺服器狀態和等,是都舉行 IDictionary < 字串、 物件 > 物件中指定的應用程式的委託。此資料結構,稱為環境字典,隨著通過管道的請求進行傳遞到元件。雖然任何鍵/值資料可能會插入到環境字典,浩然規範定義用於 HTTP,一些核心元素的鍵,如中所示圖 1

圖 1 HTTP 要求所需的環境字典鍵

 

索引鍵名稱 值描述
"owin。"RequestBody 與請求正文,如果任何一個流。Stream.Null 如果沒有請求正文,可以用作預留位置。
"owin。"RequestHeaders 請求標頭的 IDictionary < 字串、 字串 [] >。
"owin。"RequestMethod 一個包含 HTTP 要求方法的請求 (如 GET 和 POST) 的字串。
"owin。"RequestPath 包含請求路徑的字串。該路徑必須相對於應用程式委託的"根"。
"owin。"RequestPathBase 包含的部分對應于應用程式委託的"根"的請求路徑的字串。
"owin。"RequestProtocol 包含的協定名稱和版本 (如 HTTP/1.0 或 HTTP/1.1) 的字串。
"owin。"RequestQueryString 一個字串,包含查詢字串元件的 HTTP 要求的 URI,沒有前導的"?"(如 foo = 酒吧和 baz = quux)。值可能為空字串。
"owin。"RequestScheme 一個字串,包含用於 (如 HTTP 或 HTTPS) 請求的 URI 方案。

定義一組基本的環境字典的鍵-值對啟用許多不同的框架和元件作者以浩然管道中而不會強制特定.NET 物件模型,例如那些ASP.NETMVC 中的 HttpCoNtextBase 或 HttpRequestMessage/HttpResponseMessageASP.NETWeb API 中的協定進行交互操作。

這兩個元素 — — 應用程式委託和環境字典 — — 形成浩然規格。武士刀專案是基於浩然的元件和框架創建和發運由 Microsoft 的一組。

武士刀元件可以查看通過建築堆疊中描述圖 2


圖 2 武士刀專案體系結構

堆疊包含以下各層:

  • 主機:運行應用程式,可以是任何從 IIS 或一個獨立的可執行程式,對您自己的自訂程式的過程。主機負責啟動時載入的其他浩然元件和優雅地關閉。
  • 伺服器:負責將綁定到一個 TCP 埠、 構建環境字典和處理請求通過浩然管道。
  • 中介軟體:分配給所有處理請求浩然管道中的元件的名稱。它的範圍從簡單的壓縮元件到一個完整的架構,例如ASP.NETWeb API,雖然從伺服器的角度看,它是只是一種元件,公開應用程式委託。
  • 應用程式:這是您的代碼。因為武士刀不是替換為ASP.NET但而是新的方式來撰寫和主機元件、 現有ASP.NETWeb API 和 SignalR 應用程式保持不變,作為這些框架可以參加浩然管道。事實上,對於這些類型的應用程式,武士刀元件將僅在小配置類中可見。

在結構上,武士刀被分解,每一層可以輕鬆地替換,經常而不需要重新生成的代碼。在處理 HTTP 要求時,圖層一起工作的方式類似于中所示的資料流量圖 3


圖 3 的武士刀中的資料流程示例

構建現代 Web 應用程式與武士刀

現代的 Web 應用程式通常具有四個功能:

  1. 伺服器端標記代
  2. 靜態檔服務
  3. 用於處理 AJAX 請求的 web API
  4. 即時消息傳遞

建設具有所有這些功能的應用程式需要的各種不同的框架,適當地專門為相關能力。然而,構成這種框架的應用程式可以具有挑戰性,和目前需要承載于 IIS,可能孤立他們從另一個使用的應用程式和虛擬目錄的不同的應用程式部分。

相比之下,武士刀允許您撰寫現代的 Web 應用程式從範圍廣泛的不同 Web 技術,然後承載該應用程式,無論哪裡,你想下一個 HTTP 終結點公開。這提供了以下幾個好處:

  • 部署是很容易的因為它涉及只有單個應用程式而不是能力每個應用程式。
  • 您可以添加額外的功能,例如,可以將應用於所有的下游元件在管道中的身份驗證。
  • 不同的元件,無論 Microsoft 或第三-­方,可以對相同的請求狀態通過環境字典進行操作。

現在,我將探討了您應該熟悉域的應用程式範例:bug 跟蹤。該應用程式將提出一套在各種不同狀態的 bug 的 — — 積壓,工作和做 — — 請允許我以國家之間移動該 bug。,因為許多不同的個人可以同時管理 bug,bug 的狀態更改時,它將更新所有的瀏覽器在真正的時間。這裡是將用於生成該應用程式:南茜 (nancyfx.org) 的伺服器端標記代和靜態檔服務 ; ASP.NETWeb API (asp.net/web-api),處理 AJAX 請求 ; 和 SignalR (signalr.net) 的即時消息傳遞服務。

此外,雖然我不會為該瀏覽器用戶端在標記和腳本上花費大量的時間,我會使用 Knockout.js 的 Web API 和 SignalR 的資料分開的 HTML 標籤。

要記住的核心原則是我正在寫所有的這些不同的框架,納入一個單一的浩然管道,所以一旦有了新的功能我可以添加它們到應用程式只需將它們插入管道。

快速入門

武士刀的目標之一是要給你精確對添加到您的應用程式的功能 (和控制,因此,您花費在處理每個請求的性能)。考慮到這一點,我就會開始通過在Visual Studio2013年預覽中創建一個新的空ASP.NETWeb 應用程式專案中所示圖 4


圖 4 新ASP.NETWeb 應用程式專案中Visual Studio2013年預覽

Web 專案範本、 甚至空的提供非常有用的功能,在預設情況下,他們將直接進入的 /bin 資料夾,而不是 /bin/debug 資料夾 (這是共同的在其他類型的專案) 的已編譯器的集。預設的武士刀主機查找此 /bin 資料夾中的程式集。您可以創建一個基於武士刀的應用程式作為一個類庫,但您會需要要麼修改專案屬性中符合這種結構或供應您自己自訂應用程式載入程式可以搜索程式集和一個不同的資料夾結構中的類型。

接下來,我就會生成出伺服器-­使用的南茜 Web 框架的側標記生成代碼。

南茜有簡潔的語法,便於快速構建的基於 HTTP 的網站和服務。更重要的是這項工作重要的是,像ASP.NETWeb API,它沒有任何依賴項在 System.Web.dll 上,它建立在浩然管道中運行。如ASP.NETMVC 框架有依賴 System.Web.dll (撰寫本文時),讓他們少非 IIS 承載方案的理想選擇。

大多數情況下,當你向應用程式添加新功能,你會通過添加 NuGet 包。(你可以閱讀更多有關在 NuGet docs.nuget.org.)在撰寫本文時,很多的包這裡使用的是預發佈版本,因此要確保允許預發行包 NuGet 對話方塊中顯示。

要向應用程式添加南茜,我可以簡單地安裝南茜 NuGet 包。然而,因為我還想在浩然管道中運行南茜,我要去安裝 Nancy.Owin 套裝軟體 (nuget.org/packages/nancy.owin)。這將安裝南茜包作為依賴項,並提供額外的 helper 方法在我浩然管道中配置南茜。

接下來,我需要創建一個南茜模組 (類似于模型-­視圖-控制器或 MVC 中,控制器) 來處理的請求,為好的視圖以在瀏覽器中顯示的東西。這裡是模組 (HomeModule.cs) 的代碼:

public class HomeModule : NancyModule
{
  public HomeModule() {
    Get["/"] = _ => {
      var model = new { title = "We've Got Issues..." };
      return View["home", model];
    };
  }
}

正如您所看到的該模組聲明的請求定向到應用程式根目錄 ("/") 應由關聯 lambda 中定義的匿名委託進行處理。 該函數創建一個模型包含的網頁標題和指示南茜要呈現"的家"視圖中,將該模型傳遞到視圖。 視圖中,顯示在圖 5,將該模型的 title 屬性插入到頁面的標題和 h1 元素。

圖 5 Home.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>@Model.title</title>
</head>
  <body>
    <header>
      <h1>@Model.title</h1>   
    </header>
    <section>
      <h2>Backlog</h2>
      <ul class="bugs" id="backlog">
        <li>a bug</li>
      </ul>
    </section>
    <section>
      <h2>Working</h2>
      <ul class="bugs" id="working">
        <li>a bug</li>
      </ul>
    </section>
    <section>
      <h2>Done</h2>
      <ul class="bugs" id="done">
        <li>a bug</li>
      </ul>
    </section>
  </body>
</html>

有關這些清單的詳細資訊,請參閱南茜的文檔。

現在,我實現了南茜的基本功能,我需要建立一個浩然管道和配置要參加該管道的南茜模組。為此,我需要首先安裝武士刀主機和伺服器元件,然後寫少量的水暖代碼來設置浩然管道和南茜插入該管道。

武士刀主機和伺服器元件,我會首先通過使用 IIS 表達和 System.Web,如這些本質上可理解的Visual Studio和將使光滑的 F5 體驗,同時生成應用程式。若要將該專案納入 System.Web 主機,我安裝 NuGet 包 Microsoft.Owin.Host.SystemWeb (bit.ly/19EZ2Rw)。

預設武士刀元件載入和運行浩然應用程式,包括啟動類使用幾種不同的約定。武士刀主機載入時浩然的應用程式,它發現和運行啟動類基於以下規則 (按優先順序順序):

  • 如果 web.config 檔包含 appSetting 具有鍵 ="owin: AppStartup",載入程式使用該設置值。值必須是有效的。NET 類型名稱。
  • 如果程式集包含的屬性 [程式集:OwinStartup(typeof(MyStartup))],載入程式將使用指定的屬性值的類型。
  • 如果沒有這些條件,則載入程式將掃描尋找一個名為啟動時使用一種方法與簽名匹配的類型載入的程式集無效配置 (IAppBuilder app)。

對於此示例,我會允許載入程式掃描程式集的類。但是,如果您在您的專案中有很多不同的類型和程式集,它將明智地使用 appSetting 或程式集的屬性來防止不必要的掃描。

我將創建將初始化我浩然管道和作為一個管線元件添加南茜的啟動類。我創建調用啟動一個新類,並添加一種配置方法,如下所示:

public class Startup
{
  public void Configuration(IAppBuilder app)
  {
    app.UseNancy();
  }
}

UseNancy 是由 Nancy.Owin NuGet 包提供的擴充方法。儘管您可以添加中介軟體使用 IAppBuilder 的更一般的使用方法,很多中介軟體庫將提供這些輕鬆配置過程的有用的擴充方法。

此時,你可以在Visual Studio使用 f5 鍵運行該專案,看雖然它不是令人十分興奮但,你有一個全功能的 Web 應用程式。此時,浩然管道組成的單個元件,南茜,如中所示圖 6


圖 6 功能的 Web 應用程式中的單個元件

納入ASP.NETWeb API 的資料

目前,HTML 視圖包括靜態的主要標記。我現在給使用者要使用的一些真正的錯誤。許多現代 Web 應用程式,向瀏覽器用戶端提供資料的任務從伺服器端標記生成框架 (像南茜模組) 轉到一個單獨的 Web API 服務。瀏覽器,然後,載入 HTML 頁,並立即執行 JavaScript,其中從 Web API 獲取資料並動態生成 HTML 標籤在頁本身。

我將開始通過構建 Web API 使用ASP.NETWeb API 框架。像往常一樣,第一步是安裝 Web API NuGet 包。為確保我可以輕鬆地插入ASP.NETWeb API 我浩然管道,我將安裝 Microsoft.Asp­Net.WebApi.Owin 包 (bit.ly/1dnocmK)。此套裝軟體將安裝ASP.NETWeb API 框架的其餘部分作為依賴關係。在安裝後框架,我將創建一個簡單的 API 中所示圖 7

圖 7 BugsController.cs

public class BugsController : ApiController
{
  IBugsRepository _bugsRepository = new BugsRepository();
  public IEnumerable<Bug> Get()
  {
    return _bugsRepository.GetBugs();
  }
  [HttpPost("api/bugs/backlog")]
  public Bug MoveToBacklog([FromBody] int id)
  {
    var bug = _bugsRepository.GetBugs().First(b=>b.id==id);
    bug.state = "backlog";
    return bug;
  }
  [HttpPost("api/bugs/working")]
  public Bug MoveToWorking([FromBody] int id)
  {
    var bug = _bugsRepository.GetBugs().First(b => b.id == id);
    bug.state = "working";
    return bug;
  }
  [HttpPost("api/bugs/done")]
  public Bug MoveToDone([FromBody] int id)
  {
    var bug = _bugsRepository.GetBugs().First(b => b.id == id);
    bug.state = "done";
    return bug;
  }
}

該 API 包含方法從一個存儲庫,返回一組物件的 bug,以及一些的方式,不同的國家之間移動的 bug。 關於ASP.NETWeb API 的詳細資訊可以在發現 asp.net/web-api

現在,我已定義ASP.NETWeb API 控制器,我需要將它添加到我現有的浩然管道。 要這樣做,我只是添加以下行到配置方法在我啟動類中:

var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute("bugs", "api/{Controller}");
app.UseWebApi(config);

就像南茜,ASP.NETWeb API OWIN 包提供的 UseWebApi 擴充方法,使其易於ASP.NETWeb API 納入我現有的浩然管道。浩然管道現在包括如圖所示的兩個元件,ASP.NETWeb API 和南茜, 圖 8


圖 8 的兩個元件的 OWIN 管道

作為請求來入管道,如果它們匹配ASP.NETWeb API 路由規則之一,ASP.NETWeb API 處理該請求,並生成一個回應。否則,該請求通過管道,繼續在南茜試圖處理它。如果沒有管道元件可以處理特定請求,預設武士刀元件將返回一個 HTTP 404 回應。

雖正常運作的ASP.NETWeb API,它是當前不訪問的回家視圖。因此,我會添加代碼來使用來自 Web API 的資料和生成的 bug 清單中的每個不同的國家:積壓,工作和完成。對於此任務,我會好好利用的 Knockout.js,一個 JavaScript 模型-視圖-ViewModel (MVVM) 庫。挖空的詳細資訊可以在發現 knockoutjs.com

若要啟用動態,用戶端的 HTML 標籤使用挖空的一代,我需要做的第一件事是從ASP.NETWeb API 獲取的所有 bug,並創建挖空可以綁定到 HTML 元素 viewModel。如图 9 所示。

圖 9 設置 Bug viewModel

<script>
  $(function () {
    var viewModel;
    $.getJSON('/api/bugs', function(data) {
      var model = data;
      viewModel = {
        backlog: ko.observableArray(
          model.filter(function(element) { return element.state === 'backlog'; })),
        working: ko.observableArray(
          model.filter(function(element) { return element.state === 'working'; })),
        done: ko.observableArray(
          model.filter(function(element) { return element.state === 'done'; })),
        changeState: function (bug, newState) {
          var self = this;
          $.post('/api/bugs/' + newState, { '': bug.id }, function(data){
            self.moveBug(data);
          });
        },
        moveBug: function (bug) {
          // Remove the item from one of the existing lists
          ...
// Add bug to correct list
          this[bug.state].push(bug);
        }
      };
      ko.applyBindings(viewModel);
    })
  })
</script>

ViewModel 創建後,挖空可以然後動態地生成和更新的 HTML 內容通過綁定 viewModel 到裝飾著敲除特定屬性的 HTML 元素。 例如,可以從使用中所示的屬性 viewModel 生成的待辦事項清單圖 10

圖 10 屬性生成的待辦事項清單

<section>
  <h2>Backlog</h2>
  <ul class="bugs" id="backlog" data-bind="foreach:backlog">
    <li>
      [<span data-bind="text: id"></span>] <span data-bind="text: title"></span>:
        <span data-bind="text: description"></span>
      <ul>
        <li><a href="#" data-bind="click: $root.changeState.bind($root, $data,
          'working')">Move to working</a></li>   
        <li><a href="#" data-bind="click: $root.changeState.bind($root, $data,
          'done')">Move to done</a></li>   
      </ul>
    </li>
  </ul>
</section>

添加與 SignalR 的即時更改通知

此時,我有一個充分運作的單頁面 Web 應用程式。 使用者可以流覽到首頁視圖並不同 bug 狀態之間移動的 bug。 此外的基本技術的當前級別的功能,南茜和ASP.NETWeb API,正在同一浩然管道中一起運行。

我要去一步,然而,允許不同的使用者看到,在真正的時間,到 bug 其他使用者所做的更新。 為此我會利用 SignalR 庫,它提供了一個用戶端和伺服器 API 為管理瀏覽器和 Web 服務器之間的即時消息交換。 SignalR 也是寫在浩然管道中運行,因此將它添加到我的現有應用程式將是微不足道。

我會用一種稱為集線器的 SignalR 功能,雖然 SignalR 的細節超出了本文的範圍,集線器使用戶端和伺服器上另一個調用的方法。 (SignalR 的偉大簡介,請參見 bit.ly/14WIx1t.)在我的應用程式,ASP.NETWeb API 接收到請求更改 bug 的狀態時它將更新 bug,然後廣播到所有當前已連接到該應用程式的瀏覽器用戶端的更新的 bug 通過 SignalR 集線器。

我會通過在伺服器上創建一個集線器開始這一進程。 因為我不會帶任何附加的 SignalR 功能的優勢,我中心將包括只是下面的空的類定義:

[HubName("bugs")]
public class BugHub : Hub
{
}

為了從ASP.NETWeb API 發送到集線器的廣播節目,我第一次需要獲取到它的運行時上下文的實例。 通過添加以下 BugsController 建構函式,我可以這樣做:

public BugsController()
{
  _hub = GlobalHost.ConnectionManager.GetHubContext<BugHub>();
}

從內 MoveToXX 行動之一,我可以然後廣播更新的 bug 到所有的連接瀏覽器用戶端:

_hub.Clients.All.moved(bug);

在主視圖中,添加幾個腳本引用到的 SignalR JavaScript 庫後, 我可以連接到 bugsHub,並開始監聽"感動"與以下消息:

$.connection.hub.logging = true;
var bugsHub = $.connection.bugs;
bugsHub.client.moved = function (item) {
  viewModel.moveBug(item);
};
$.connection.hub.start().done(function() {
  console.log('hub connection open');
});

請注意當從伺服器將通過移動功能接聽,我 viewModel moveBug 在調用方法我在該專案的 click 處理常式中一樣的方法。 不同的是因為此方法是 SignalR 廣播的結果,所有的瀏覽器用戶端可以在同一時間更新其 viewModels。 通過打開兩個瀏覽器視窗,可以清楚地看到這,在其他中的一個,進行更改,然後查看狀態更改。

如上所述,將 SignalR 添加到浩然管道是微不足道的。 只需添加啟動類配置方法如下:

app.MapSignalR();

這將創建一個管道中的一個像圖 11


圖 11 OWIN 管道同三個元件

移動到自主辦

我現在有一個功能的 bug 管理應用程式,同時仍然缺少一些關鍵的功能,可以做一些有趣的事情。我以增量方式已經向應用程式添加功能,通過使用 Microsoft 和協力廠商武士刀中介軟體元件。然而,這已經是今天使用的ASP.NETHttpModules 和 HttpHandlers 可能。所以什麼我真的完成,提供一種更簡單、 代碼驅動的方法撰寫的管道元件?

關鍵是要記住的高級別的武士刀的體系結構關係圖中圖 2。到目前為止,我只一直在的武士刀堆疊頂部的兩個圖層。然而,所有這些層可以方便地替換,包括伺服器和主機。

為了演示,我就會把我整條管線、 使它擺脫 IIS 和 System.Web.dll,和它坐在一個簡單的、 羽量級的 HTTP 伺服器,正在主辦一把武士刀可執行檔,命名為 OwinHost.exe。自託管可以證明有用的各種方案,從設置那裡有沒有在開發電腦上,對生產情況在共用主控環境中,它使用進程隔離並不公開訪問 Web 服務器部署的應用程式正在安裝的 Web 服務器。

我會開始通過安裝下列額外 NuGet 包:

我然後就會重新生成應用程式。請注意運行在一個新的伺服器和主機應用程式不需要重建。唯一的要求是在運行時,在的 /bin 資料夾中存在的那些檔和重建是有的檔會被覆制到 /bin 的便捷途徑。

已安裝的套裝軟體和複製的檔後,我打開一個命令提示符,導航到 Web 專案的根資料夾,和所示圖 12,在包資料夾內調用來自 OwinHost.exe:

> ..
\packages\OwinHost.2.0.0\tools\OwinHost.exe


圖 12 在包資料夾內調用從 OwinHost.exe

預設情況下,OwinHost.exe 將啟動、 載入 Microsoft.Ow­中。Host.HttpListener 伺服器上,並開始偵聽埠 5000。然後我可以導航到 HTTP://localhost:5000 以確認整個應用程式正在運行。

此外,幾乎所有的預設設置可以重寫使用命令列開關。例如,如果您想要在一個不同的埠上偵聽,供應-p 12345。如果您想要使用一個完全不同的伺服器,請使用-s your.custom.server.assembly。武士刀設計的力量是其模組化設計。作為創新發生在堆疊的任何層,他們可以立即集成到運行的應用程式。因為堆疊的所有元件之間的合同是很簡單的應用程式的委託,創新的步伐可以遠遠大於現在是什麼可用。

剛開始

武士刀 2.0 將發佈Visual Studio2013年。新版本有兩個主要重點領域:

  • 為自託管提供核心基礎結構元件
  • 對於身份驗證,包括 Windows Azure Active Directory、 cookie 和聯邦社會供應商如 Facebook、 谷歌、 推特和 Microsoft 帳戶,以及供應商提供一套豐富的中介軟體

武士刀 2.0 釋放之後,工作會立即開始下一集的武士刀元件。尚待確定的詳細資訊和優先事項,但是你可以通過提出問題在影響這種討論 katanaproject.codeplex.com。最後,所有的這篇文章的代碼可以在發現 bit.ly/1alOF4m

HowardDierking是在 Windows Azure 框架和工具,團隊的專案經理他的工作重點在哪裡ASP.NET、 NuGet 和 Web Api。 以前,Dierking擔任 MSDN 雜誌的主編,並為 Microsoft 學習也跑,開發人員認證計畫。他花了 10 年前微軟作為一個開發人員和應用程式具有焦點建築師分散式系統。

衷心感谢以下 Microsoft 技术专家对本文的审阅:布萊迪胃和Scott靜態