經過上個篇幅的學習瞭解Model綁定的基礎知識,然而在ASP.NET Web API中Model綁定功能模塊並非被直接調用的,而是要經過本篇要介紹的內容ParameterBinding的一系列對象對其進行封裝調用,經過本篇的學習以後也會大概的清楚在Web API中綁定會有哪幾種方式。api
在ASP.NET Web API中ParameterBinding表明着參數綁定而且在這其中涉及了幾種綁定的方式,然而ParaMeterBinding並非單獨執行的,就比如一個控制器方法中有可能會有多個參數同樣,因此咱們就先來看一下ActionBinding的相關對象,對於這些對象的生成的環境以及過程咱們在後面的篇幅中會有講解。數組
HttpActionBinding服務器
代碼1-1ide
namespace System.Web.Http.Controllers { public class HttpActionBinding { public HttpActionBinding(); public HttpActionBinding(HttpActionDescriptor actionDescriptor, HttpParameterBinding[] bindings); public HttpActionDescriptor ActionDescriptor { get; set; } public HttpParameterBinding[] ParameterBindings { get; set; } public virtual Task ExecuteBindingAsync(HttpActionContext actionContext, CancellationToken cancellationToken); } }
代碼1-1中對於HttpActionBinding類型的定義一目瞭然,看HttpActionBinding類型的重載構造函數中有HttpActionDescriptor類型、HttpParameterBinding類型的數組類型做爲參數,HttpActionDescriptor類型做爲控制器方法描述類型你們已經很熟悉了吧,這個類型中包含着控制器方法的元數據信息,然後者HttpParameterBinding類型則是表示着參數綁定對象,其實在Model綁定中每一個參數的綁定都是經過ParameterBinding來綁定的,因此這裏的執行過程咱們暫時不去深刻了解,就是單純的瞭解一下相關的對象模型。函數
HttpParameterBinding學習
代碼1-2spa
namespace System.Web.Http.Controllers { public abstract class HttpParameterBinding { protected HttpParameterBinding(HttpParameterDescriptor descriptor); public HttpParameterDescriptor Descriptor { get; } public virtual string ErrorMessage { get; } public bool IsValid { get; } public virtual bool WillReadBody { get; } public abstract Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken); protected object GetValue(HttpActionContext actionContext); protected void SetValue(HttpActionContext actionContext, object value); } }
在代碼1-2中咱們看到HttpParameterBinding類型的定義,能夠看到HttpParameterBinding是抽象類型,而且實現綁定的方法ExecuteBindingAsync()也是抽象的,這也是爲了在不一樣的環境和狀況相愛採起不一樣的綁定機制作好鋪墊就是多態啦,這個咱們後面會說,咱們仍是先看下HttpParameterBinding類型的內部定義,首先咱們看到的是構造函數中的參數類型,HttpParameterDescriptor類型,又是一個對象描述類型,此次的描述對象則是控制其方法中的某個參數,而HttpParameterBinding對象實例的生成則是根據HttpParameterDescriptor對象實例而來,這個後續的篇幅中會有講解。ErrorMessage屬性表示在ParameterBinding綁定的過程當中出現的錯誤信息,而IsValid屬性表示綁定是否能夠完成的依據就是判斷ErrorMessage屬性是否爲Null,WillReadBody屬性表示ParameterBinding對象是否讀取Http消息正文內容做爲參數綁定的數據源,這個稍後給你們看的示例中就有,一看便知。GetValue()和SetValue()方法就是向當前HttpActionContext中獲取對應的參數值和設置參數對應值。code
ModelBinderParameterBindingorm
代碼1-3對象
namespace System.Web.Http.ModelBinding { public class ModelBinderParameterBinding : HttpParameterBinding, IValueProviderParameterBinding { public ModelBinderParameterBinding(HttpParameterDescriptor descriptor, IModelBinder modelBinder, IEnumerable<System.Web.Http.ValueProviders.ValueProviderFactory> valueProviderFactories); public IModelBinder Binder { get; } public IEnumerable<System.Web.Http.ValueProviders.ValueProviderFactory> ValueProviderFactories { get; } public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken); } }
代碼1-3表示的是ModelBinderParameterBinding類型,這個類型表明的綁定方式(綁定的數據來源)是經過IModelBinder來獲取的,也就正如代碼1-3中咱們看到的構造函數同樣,其中有IModelBinder和ValueProviderFactory類型的集合,這些就是數據綁定的數據源。Binder屬性和ValueProviderFactories屬性也就是構造函數傳入的兩個類型值。對於綁定的細節這裏就不說多了。
FormatterParameterBinding
代碼1-4
namespace System.Web.Http.ModelBinding { public class FormatterParameterBinding : HttpParameterBinding { public FormatterParameterBinding(HttpParameterDescriptor descriptor, IEnumerable<MediaTypeFormatter> formatters, IBodyModelValidator bodyModelValidator); public IBodyModelValidator BodyModelValidator { get; set; } public override string ErrorMessage { get; } public IEnumerable<MediaTypeFormatter> Formatters { get; set; } public override bool WillReadBody { get; } public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken); public virtual Task<object> ReadContentAsync(HttpRequestMessage request, Type type, IEnumerable<MediaTypeFormatter> formatters, IFormatterLogger formatterLogger); } }
代碼1-4中所示的FormatterParameterBinding類型是經過哪一種方式來獲取綁定數據源的呢?你們能夠看到WillReadBody屬性在這個類型中被重寫了,原來在HttpParameterBinding類型中默認爲false的是不會對Http請求的正文內容進行讀寫的,而這裏在FormatterParameterBinding類型中,已然的重寫了,說明在這個類型中咱們所能用到的綁定數據源就是從Http請求的正文內容來讀取了,然而Http請求的正文內容並非直接放在那裏供咱們讀取的,而是在客戶端發送前就已經被指定的序列化器序列化了。
那麼咱們在服務器端就要反序列化才能獲取到值,這裏在代碼1-4中咱們看到構造函數中能夠看到和代碼1-3同樣都是具備一個HttpParameterDescriptor類型的參數對象,然後則是一個MediaTypeFormatter類型的集合對象,最後是進行Model驗證的對象,這個後續再說。
如今咱們就來看看第二個參數類型中的MediaTypeFormatter類型。
MediaTypeFormatter
代碼1-5
namespace System.Net.Http.Formatting { public abstract class MediaTypeFormatter { protected MediaTypeFormatter(); public abstract bool CanReadType(Type type); public abstract bool CanWriteType(Type type); public virtual Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger); public virtual Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext); } }
在代碼1-5中所示的MediaTypeFormatter類型是被刪減過的一部分,所剩4個方法中兩個是抽象方法兩個是虛方法,先看兩個抽象方法的定義,CanReadType()方法表示的是根據指定的參數類型從當前的Http請求正文中可否讀取到改類型的值,簡單來講就是可否把正文內容反序列化爲指定的參數類型,同理CanWriterType()是對響應正文進行操做判斷。而ReadFromStreamAsync()方法和WriteToStreamAsync()方法則是對Http請求正文內容和Http響應正文內容進行實際操做的兩個方法。
對於MediaTypeFormatter類型的實現類型好比說針對Json格式的JsonMediaTypeFormatter和針對Xml格式的XmlMediaTypeFormatter.
咱們看一下JsonMediaTypeFormatter類型的簡單示例,你們就會知道是怎麼回事了。
首先咱們在服務器端的控制器中定義一個接收Post請求的方法,
代碼1-6
[CustomControllerActionAuthorizationFilter] public void Post(Product product) { products.Add(product); }
爲了方便演示在其控制其方法上加了個受權過濾器,而後咱們對Post請求的處理使用JsonMediaTypeFormatter類型進行反序列化的操做將在CustomControllerActionAuthorizationFilter過濾器類型中進行。
代碼1-7
public Task<System.Net.Http.HttpResponseMessage> ExecuteAuthorizationFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>> continuation) { Console.WriteLine(actionContext.Request.Content.Headers.ContentType.MediaType); IEnumerable<MediaTypeFormatter> formatters = new MediaTypeFormatter[] { new JsonMediaTypeFormatter() }; Product product = actionContext.Request.Content.ReadAsAsync<Common.Product>(formatters).Result; Console.WriteLine(product.ProductID); Console.WriteLine(product.ProductName); Console.WriteLine(product.ProductCategory); return continuation(); }
在代碼1-7中,在請求到達控制器方法以前會先通過受權過濾器,在這其中首先咱們是先向服務器端的控制器輸出了當前請求的格式類型,而後就對當前請求的正文內容使用JsonMediaTypeFormatter類型進行反序列化操做。
咱們再看下客戶端使用HttpClient類型進行模擬Post請求,
代碼1-8
HttpClient httpClient = new HttpClient(); Product product = new Product() { ProductID = "003", ProductName = "旺仔牛奶", ProductCategory = "食品類" }; await httpClient.PostAsJsonAsync<Product>("http://localhost/selfhost/api/product", product);
最後結果如圖1.
圖1
看到這裏想必你們也知道對於XmlMediaTypeFormatter的使用方式是怎樣的了。
還有一種MediaTypeFormatter類型FormUrlEncodedMediaTypeFormatter類型,FormUrlEncodedMediaTypeFormatter類型表示的是在Http Post請求中表單提交的數據所用格式器,咱們看一下FormUrlEncodedMediaTypeFormatter類型中CanReadType()方法的實現。
代碼1-9
public override bool CanReadType(Type type) { if (type == null) { throw Error.ArgumentNull("type"); } if (!(type == typeof(FormDataCollection))) { return FormattingUtilities.IsJTokenType(type); } return true; }
在代碼1-9咱們能夠看到FormDataCollection類型實際就是IEnumerable<KeyValuePair<string, string>>類型的對象,在表單提交後的請求Url中你們也均可以看到是是key=value的形式,因此這裏就是這種格式的。對於這個格式器的示例會在後面的篇幅給你們作演示講解。
HttpRequestParameterBinding
最後咱們再看一個RequestParameterBinding對象。
代碼1-10
public class HttpRequestParameterBinding : HttpParameterBinding { // Methods public HttpRequestParameterBinding(HttpParameterDescriptor descriptor) : base(descriptor) { } public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) { string parameterName = base.Descriptor.ParameterName; HttpRequestMessage request = actionContext.ControllerContext.Request; actionContext.ActionArguments.Add(parameterName, request); return TaskHelpers.Completed(); } }
在代碼1-10中咱們看到再ExecuteBindingAsync()方法的實現中,是直接獲取到參數名稱和當前的請求對象,而後添加到控制其方法執行上下文的ActionArguments屬性中,在以前的篇幅中也說過這個屬性用來存放方法對應參數值(Model綁定後的值)。
本篇關於ParameterBinding的對象介紹就到這裏,都是零零散散的不過在後面的篇幅中都會有示例介紹說明的。
做者:金源
出處:http://www.cnblogs.com/jin-yuan/
本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面