|
本文將概述在WebAPI方式下將如何將參數(shù)綁定到一個action方法,包括參數(shù)是如何被讀取,一系列規(guī)則決定特定環(huán)境采用的那種綁定方式,文章最后將給出一些實際的例子。 Parameter binding說到底是接到一個Http請求,將其轉換成.NET類型使得action方法的簽名更易于理解。 請求消息(request message)包括了請求的所有信息,如帶查詢字符串的請求地址(URL),內(nèi)容主體(content body)及頭部信息(header)。在沒有采用parameter binding 的情況下,每個action方法將需要接收request message,并手動從中提取出參數(shù),如下所示: public object MyAction(HttpRequestMessage request)
{
// make explicit calls to get parameters from the request object
int id = int.Parse(request.RequestUri.ParseQueryString().Get("id")); // need error logic!
Customer c = request.Content.ReadAsAsync<Customer>().Result; // should be async!
// Now use id and customer
}
很顯然,這樣的方式丑陋,易出錯,代碼重復,而且難以單元測試。我們希望action的簽名類似以下的形式: public object MyAction(int id, Customer c) { }
那么WebAPI是如何將request message轉換成像id和customer這樣的參數(shù)的呢? Model Binding vs. Formatters參數(shù)綁定有兩種技術:Model Binding和Formatters。實際上,WebAPI使用model binding讀取查詢字符串(query string)內(nèi)容進行參數(shù)綁定,使用Formatters讀取主體內(nèi)容 (body content)進行參數(shù)的綁定。
ModelBinding和MVC中的此概念是一致的,更多內(nèi)容見Here。通常有一個"ValuePeoviders"提供數(shù)據(jù)片斷如查詢字符串參數(shù),model binder將這些片斷組合成一個對象。
Formatters(如MediaTypeFormatter類所示)實際上是包含額外元數(shù)據(jù)的序列化程序。WebAPI從HttpConfiguration中獲取一個formatters的列表,然后通過request信息 中的content-type來判斷采用具體合適的formatter。WebAPI有不少默認的formatters。默認的JSON formatter是JSON.NET。還有Xml formatter和采用JQuery語法的 FormUrl formatter。 其中Formatters的核心方法是MediaTypeFormatter.ReadFromStreamAsync,如下所示: public virtual Task<object> ReadFromStreamAsync( 其中,Type指代參數(shù)的類型,將傳遞給序列化器serializer。Stream是請求信息的content stream。Read方法將讀取stream,將其實例化為一個對象,然后返回它。 HttpContentType來自請求信息。IFormatterLogger是一個回調接口,fomatter正是通過此接口來記錄讀取中的錯誤。 model binding和formatter都支持驗證和錯誤信息記錄。然后,相比formatter而言model binding更靈活。 何時采用特定的參數(shù)綁定方式?(when do we use which?)以下這些基本原則決定了parameter是通過modelbinding還是formatter來讀取的: 如果參數(shù)未添加任何特性字段[attribute]標明,那么這將由參數(shù)的.NET類型來決定具體采用何種方式。簡單類型"Simple types"采用model binding。復雜類型"Complex types"
以下是使得這些原則得以穩(wěn)定并可預測的關鍵設計。 (body 只能被讀取一次)Only one thing can read the bodyMVC和WebAPI之間的一個關鍵不同點在于MVC緩存請求主體(request body)。這意味著MVC的參數(shù)綁定可以反復從body中查找參數(shù)片斷。然而,在WebAPI中,請求主體(HttpContent) 只能被讀取一次,不被緩存,只能向前讀取的流。這意味著parameter binding需要謹慎對待stream,除非在需要綁定參數(shù)的情況下,否則stream不能被讀取。 以下的action方法想直接讀取stream,因而導致WebAPI不能保證其擁有用于參數(shù)綁定的stream??紤]如下的action方法: // Action saves the request’s content into an Azure blob
public Task PostUploadfile(string destinationBlobName)
{
// string should come from URL, we’ll read content body ourselves.
Stream azureStream = OpenAzureStorage(destinationBlobName); // stream to write to azure
return this.Request.Content.CopyToStream(azureStream); // upload body contents to azure.
}
參數(shù)是一個簡單類型,因而這將從查詢字符串中讀取。由于action簽名中并不包含任何 負責類型,WebAPI將永遠不會讀取request content stream,因而這里的action方法可以讀取它。 示例以下給出一些不同請求的示例說明它們將如何映射到特定action簽名: /?id=123&name=bob
/?id=123&name=bob void Action([FromBody] string name); //[FormBody]特性顯示標明讀取整個body為一個字符串作為參數(shù) public class Customer { // 定義的一個復雜對象類型 /?id=123 void Action(Customer c1, Customer c2) // 出錯!多個參數(shù)都是復雜類型,都試圖從body中讀取,而body只能被讀取一次 void Action([FromUri] Customer c1, Customer c2) // 可以!不同于上面的action,復雜類型c1將從url中讀取,c2將從body中讀取 void Action([ModelBinder(MyCustomBinder)] SomeType c) // 標示使用特定的model binder來解析參數(shù) [ModelBinder(MyCustomBinder)] public class SomeType { } // 通過給特定類型SomeType聲明標注[ModelBidner(MyCustomBinder)]特性使得所有SomeType類型參數(shù)應用此規(guī)則 void Action(SomeType c) // 由于c的類型為SomeType,因而應用SomeType上的特性決定其采用model binding 與MVC的區(qū)別以下是MVC和WebAPI在參數(shù)綁定上的一些不同點:
|
|
|