本文章是由機器翻譯。

切削刃

ASP.NET MVC 開發人員的內容交涉和 Web API

Dino Esposito

Dino Esposito我最喜歡ASP.NETMVC 中的事情之一是能夠公開的方法,可以輕鬆地調用從 HTTP 用戶端,包括基於 jQuery 頁面、 移動應用程式和平原 C# 後端的門面。很長時間,為建立這一服務層發生在 Windows 通信基礎 (WCF) 服務領域。試圖專門為 HTTP,WCF webHttpBinding 機制和框架,如現在退休休息初學者工具組的介紹等。這些方法都沒有不過,真的可以消除開發人員設置路障臭名遠揚 WCF 過度配置、 過度使用的屬性和一個不是專門設計的可測試性的結構等。然後來了 Web API — 一個新的框架,設計為薄、 可測試、 獨立于主控環境 (例如,IIS) 和 HTTP 為重點。

但是,Web API 有一個程式設計介面,看起來幾乎太類似于ASP.NETMVC 中,在我的意見。這不是一個負面評論,不過,作為ASP.NETMVC 具有清潔和定義良好的程式設計介面。Web API 其實開始用一種看上去類似于 WCF,然後成長為類似于ASP.NETMVC 程式設計模型。

在本文中,我會在表示加上平原ASP.NETMVC Web API 的功能區提供一個視圖的 Web API 從平均ASP.NETMVC 開發人員和焦點的角度:內容協商。

Web API,一目了然

Web API 是你可以使用來創建一個庫的類可以處理的 HTTP 要求的一個框架。結果庫,以及一些初始配置設置,可以在運行時環境中承載並通過 HTTP 調用方所消耗。對控制器類的公共方法成為 HTTP 端點。可配置路由規則説明定義表單的 Url 用於訪問特定的方法。然而,除了路由,什麼定義的預設表單的 URL 處理 Web API 中的大部分是公約 》,而不是配置。

如果你是一個ASP.NETMVC 開發者,此時您可能不要讀了,不知道為什麼關於地球你會想要使用一個新框架,似乎只是重複的控制器的概念你在ASP.NETMVC 中"已經"。

是的對那快速的答案是,你大概不需要 Web API 在ASP.NETMVC,因為你可以實現通過平原控制器幾乎相同的功能。例如,您可以輕鬆地返回資料的格式設置為 JSON 或 XML 的字串。您可以輕鬆地返回二進位資料或純文字。您可以創建您最喜歡的 URL 範本形狀。

相同的控制器類可以服務 JSON 資料或 HTML 視圖,並且您可以輕鬆地單獨的控制器,從控制器只是返回的資料中返回 HTML。事實上,常見的做法是在專案中有一個 ApiController 類哪裡你這些預期返回普通資料的所有終結點。下面是一個示例:

public class ApiController : Controller {
public ActionResult Customers()
{
  var data = _repository.GetAllCustomers();
  return Json(data, JsonRequestBehavior.AllowGet);  }
  …
}

Web API 使用最好的ASP.NETMVC 體系結構,提高它在兩個主要領域。 第一,它引入了一個新的邏輯層,稱為內容協商與一組標準的規則是否請求資料在一個給定的格式,JSON、 XML 或其他格式。 第二,Web API 沒有任何依賴項任何ASP.NET和 IIS 上 — 更具體地說,它有沒有依賴項的 system.web.dll 庫上。 當然它可以在 IIS 下ASP.NET應用程式中承載。 然而,雖然這仍可能是最常見的情況,可以提供特設的主控環境中,如 Windows 服務,一個Windows Presentation Foundation(WPF) 應用程式或主控台應用程式的任何其他應用程式中承載 Web API 庫。

同時,如果你是一個專家ASP.NETMVC 開發者,控制器,Web API 概念模型綁定、 路由選擇和操作篩選器將會對你非常熟悉。

為什麼 Web 表單開發人員愛 Web API

如果你是一個ASP.NETMVC 開發者,你可能最初迷糊方面的益處的 Web API 因為其程式設計模型看起來到ASP.NETMVC 幾乎完全相同。 但是,如果您是 Web 表單的開發人員,你不應該感到困惑。 與 Web API 公開 HTTP 端點從 Web 表單應用程式中的是一個孩子的遊戲。 所有這些都添加類似于下面的一個或多個類:

public class ValuesController : ApiController
{
  public IEnumerable<string> Get()
  {
    return new string[] { "value1", "value2" };
  }
  public string Get(int id)
  {
    return "value";
  }
}

請注意這是您將使用ASP.NETMVC 應用程式中添加一個 Web API 控制器相同的代碼。 您還必須指定路線。 這裡的一些你想要在應用程式啟動時運行的代碼:

RouteTable.Routes.MapHttpRoute(
  name: "DefaultApi",
  routeTemplate: "api/{controller}/{id}",
  defaults: new { id = System.Web.Http.RouteParameter.Optional });

除非另有注明用 NonAction 屬性,匹配的預設命名的類和路由公約任何公共方法都是公共的 HTTP 調用終結點。 他們可以從任何用戶端無需生成的代理類、 web.config 引用或特殊的代碼調用。

Web API 中的路由約定規定 URL 開頭 /api 後面的控制器名稱。 請注意沒有明確表示的操作名稱。 操作確定所請求的類型,是否得到,放,郵寄或刪除。 始于 Get、 放、 職位或刪除的方法的名稱是常規地映射到相應的操作。 例如,GetTasks 在 TaskController 上的一種方法將調用到如 /api/task 的 URL 的任何 GET 請求。

無論明顯名字相似的行為和類與ASP.NETMVC 中,在一組完全單獨的程式集和使用的 Web API 生活一套完全不同的 types—System.Net.Http 是主集。

內部 Web API 內容談判

"內容協商"通常用於描述進程的檢查傳入的 HTTP 要求來弄清楚,在用戶端希望接收的回應的格式的結構。 從技術上講,不過,內容協商是用戶端和伺服器確定最佳的可能表示格式,在它們的交互中使用的過程。 檢查請求通常是指看著幾個如接受和內容類型的 HTTP 標頭。 尤其是,內容類型、 用於郵政和付諸表決的請求的處理伺服器上和用戶端選擇 HTTP 回應的格式化程式。 內容類型不用於 GET 請求。

然而,內容協商的內部機制是複雜得多。 上述方案是最典型 — 由於預設慣例和實現 — 但它不是只有一種可能。

控制 Web API 中的談判進程的元件是調用 DefaultContentNegotiator 的類。 它實現了一個公共介面 (IContentNegotiator),所以您可以替換它完全如果需要。 在內部,預設談判代表適用幾個獨特的標準找出回應的理想格式。

談判專家工作的註冊媒體清單類型格式化程式 — 實際上將物體變成一種特定格式的元件。 談判專家經過格式化程式和停在第一個匹配項的清單。 格式化程式有幾種的方法,讓談判專家知道它可以序列化當前請求的回應。

第一次檢查發生在 MediaTypeMappings 集合,它是由中所有預定義的媒體類型格式化程式的預設值為空的內容上。 媒體類型映射表示一個條件,如果驗證的有權的格式化程式來序列化正在處理的請求的回應。 有幾個預定義的媒體類型映射。 其中一個看起來在查詢字串中的特定參數。 例如,您可以啟用 XML 序列化,只要求一個 xml = true 運算式添加到用於調用 Web API 的查詢字串。 對於這種情況發生,您需要在您的自訂 XML 媒體類型格式化程式的建構函式中有以下代碼:

MediaTypeMappings.Add(new QueryStringMapping("xml", "true", "text/xml"));

以類似的方式,你可以有調用方表達自己的偏好,通過向 URL 添加擴展或添加自訂的 HTTP 標頭:

MediaTypeMappings.Add(new UriPathExtensionMapping("xml", "text/xml"));
MediaTypeMappings.Add(new RequestHeaderMapping("xml", "true",
  StringComparison.InvariantCultureIgnoreCase, false,"text/xml"));

對於 URL 路徑擴展,這意味著下面的 URL 將映射到 XML 格式化程式:

http://server/api/news.xml

請注意對於 URL 路徑擴展外掛程式,以你的工作需要有特設的路線如:

config.Routes.MapHttpRoute(
  name: "Url extension",
  routeTemplate: "api/{controller}/{action}.{ext}/{id}",
  defaults: new { id = RouteParameter.Optional }
);

為自訂的 HTTP 標頭,RequestHeaderMapping 類的建構函式接受了頭、 其預期值和幾個額外的參數的名稱。 一個可選參數,指示所需的字串比較模式,和另一種是一個布林值,該值指示是否比較是對整個字串。 如果談判不能找到匹配項上格式化程式使用的媒體類型映射資訊,看起來在接受和內容類型的標準 HTTP 標頭。 如果沒有找到匹配項,它再次經過註冊的格式化程式的清單並檢查是否請求的返回類型可以由一個格式化程式序列化。

若要添加自訂格式化程式,在啟動的應用程式 (例如,在 Application_Start 方法) 中插入下面的代碼類似:

config.Formatters.Add(xmlIndex, new NewsXmlFormatter());

自訂的談判進程

大多數情況下,媒體類型映射讓您輕鬆地完成序列化的任何特別要求。 然而,你總是可以通過編寫派生的類和重寫 MatchRequestMediaType 方法來替換預設內容談判代表:

protected override MediaTypeFormatterMatch MatchRequestMediaType(
  HttpRequestMessage request, MediaTypeFormatter formatter)
{
  ...
}

您可以創建一個完全自訂的內容談判與實現 IContentNegotiator 介面的新類。 一旦你有一個手工製作的談判者,你註冊 Web API 的運行時:

GlobalConfiguration.Configuration.Services.Replace(
  typeof(IContentNegotiator),
  new YourOwnNegotiator());

前面的代碼通常都是在 global.asax 或中的這些方便的配置處理常式Visual Studio將在ASP.NETMVC Web API 專案範本為您創建一個。

控制內容的格式從用戶端

內容協商的 Web API 中最常見的情況是當使用接受頭時。 這種方法使得內容格式完全透明 Web API 代碼。 調用方的接受標頭進行相應的設置 (例如,為 text/xml) 和 Web API 基礎設施進行相應處理。 下面的代碼演示如何將接受標頭設置在 jQuery 調用到 Web API 的終結點來拿回一些 XML 中:

$.ajax({
  url: "/api/news/all",
  type: "GET",
  headers: { Accept: "text/xml; charset=utf-8" }
});

在 C# 代碼中,您設置接受頭象這樣:

var client = new HttpClient();
client.Headers.Add("Accept", "text/xml; charset=utf-8");

在任何程式設計環境中的任何 HTTP API 允許您設置的 HTTP 標頭。 如果你預見到你可以有調用方凡這可能是一個問題,最佳的做法是還添加媒體類型映射所以 URL 包含所有所需的資訊內容的格式。

銘記,回應嚴格取決於結構的 HTTP 要求。 請嘗試請求 Web API URL 從網址列的 Internet Explorer 10 和鉻。 Don不會感到驚訝,看到你 JSON 在一個案子和 XML 在其他。 預設 Accept 頭可能會在不同的瀏覽器不同。 一般情況下,如果將由協力廠商公開使用 API,你應當有一個基於 URL 的機制選擇的輸出格式。

使用 Web API 的情形

體系結構上講,Web API 是邁出的一大步。 它變得更重要與.NET (浩然) NuGet 包最近開放的 Web 介面 (Microsoft.AspNet.Web­­Api.Owin) 和專案武士,便利承載 API 在外部應用程式通過一組標準的介面。 如果您正在構建非ASP.NETMVC 應用程式的解決方案,使用 Web API 是一個沒有腦子。 但基於ASP.NETMVC Web 解決方案中使用 Web API 的意義是什麼?

與平原ASP.NETMVC,可以輕鬆構建 HTTP 門面不學習新的東西。 你可以談判內容相當輕鬆地與一點點的代碼在一些控制器基類或在需要它的任何方法 (或通過創建通過談判達成的一個)。 這是行動方法簽名中有一個額外的參數、 檢查它,然後相應地序列化到 XML 或 JSON 回應一樣容易。 此解決方案是實用的只要你限制自己使用 XML 或 JSON。 但如果您有更多的格式,要考慮到,您可能需要使用 Web API。

如前文所述,可以在 IIS 承載 Web API — 例如,在 Windows 服務中。 顯然,如果 API 生活ASP.NETMVC 應用程式中,你要綁定到 IIS。 類型的託管因此取決於您正在創建的 API 層的目標。 如果它註定要消耗僅由周圍ASP.NETMVC 網站,那你可能不需要 Web API。 如果您創建的 API 層真是公開的 API 的一些商業背景下的"服務",然後在ASP.NETMVC 中使用的 Web API 意義的好。

Dino Esposito 是"構建移動解決方案的企業"(微軟出版社,2012年) 的作者和即將舉行"程式設計ASP.NETMVC 5"(Microsoft Press)。為.NET 和 Android 平臺在 JetBrains 和經常在世界各地的行業活動發表演講的技術傳教士,埃斯波西托共用的軟體,他的理想 software2cents.wordpress.com 和在 Twitter 上 twitter.com/despos

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