WebApi 通过ModelBinder绑定自定义参数对象
绑定action内参数对象的方法有很多种,无论是针对简单对象,还是复杂对象。比如 typeConverter 有兴趣的,可以看看我其他文章
但是如果需要在绑定参数的过程中进行某些验证,或者绑定对象的数据并不单单来源于用户传过来的值,比如获取请求的所有Cookie对象等等
这种情况的话,比 typeConverter 更好的方法就是自定义ModelBinder,那么实际WebApi绑定参数的流程是怎么样的呢。
通过 ValueProviderFactory 获得 ValueProvider
调用ValueProvider类里面ContainsPrefix方法,判定 ValueProvider 是否包含参数 的名称key
如果包含,那么
通过在类上定义的ModelBinder类,调用ModelBinder类的BindModel方法
在BindModel方法内 通过 bindingContext.ValueProvider获取
定义在action内描述参数特性的ValueProvider,比如[ValueProvider(typeof(DictionaryValueProviderFactory))]
ValueProviderResult result = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
通过bindingContext.ModelName 获取参数名称,继而调用ValueProvider.GetValue,获取ValueProvider内key对应的对象,并封装成ValueProviderResult 返回
将 ValueProviderResult.rawValue 赋给Model,那么参数就会被绑定model的值
bindingContext.Model = ValueProviderResult.rawValue
先上前台页面
Client端代码
private void button2_Click(object sender, EventArgs e) { HttpWebRequest request=(HttpWebRequest) WebRequest.Create("http://localhost:29828/api/Demo"); request.Method = "GET"; Cookie c = new Cookie("name", "zhangsan", "/api", "localhost"); c.Expires = DateTime.Now.AddDays(1); Cookie c2 = new Cookie("psd", "123456", "/", "localhost"); c2.Expires = DateTime.Now.AddDays(1); CookieContainer cookies = new CookieContainer(); request.CookieContainer = cookies; request.CookieContainer.Add(c); request.CookieContainer.Add(c2); //通过URL传值的话,可以不指定 contentType //request.ContentType = "text/html;charset=utf-8"; //request.ContentType = "application/x-www-form-urlencoded;charset=utf-8"; using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { using (StreamReader reader = new StreamReader(response.GetResponseStream())) { string result = reader.ReadToEnd(); this.textBox1.Text = result; } foreach (Cookie item in response.Cookies) // 获取 服务器传回的Cookie { this.textBox1.Text += item.Name; this.textBox1.Text += item.Value; } } }
看Server端代码结构
using System.Web.Http; using System.Web.Http.ValueProviders; using WebApi.Models; namespace WebApi.Controllers { public class DemoController : ApiController { public LoginCookieUser Get2([ValueProvider(typeof(CookieValueProviderFactory))] LoginCookieUser name) { return name; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http.ModelBinding; using System.Runtime.Serialization; namespace WebApi.Models { [ModelBinder(typeof(CookieValueModelBinder))] [DataContract] public class LoginCookieUser { [DataMember] public string loginuser { get; set; } [DataMember] public string Domain { get; set; } [DataMember] public DateTime Expires { get; set; } [DataMember] public string Path { get; set; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http.Controllers; using System.Web.Http.ModelBinding; using System.Web.Http.ValueProviders; using WebApi.Models; namespace WebApi { public class CookieValueModelBinder : IModelBinder { public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) { ValueProviderResult result = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); if (result == null) { return false; } object rawValue = result.RawValue; LoginCookieUser user = new LoginCookieUser(); user.loginuser = result.RawValue.ToString(); if (bindingContext.ModelType.IsInstanceOfType(user)) { //如果ModelMetadata的ConvertEmptyStringToNull属性为True //并且原始类型是一个空白字符串 //将绑定的Model对象设置为Null if (rawValue is string && string.IsNullOrWhiteSpace((string)rawValue) && bindingContext.ModelMetadata.ConvertEmptyStringToNull) { rawValue = null; } bindingContext.Model = user; //向客户端传送Cookie var cookie = new HttpCookie("servercookie", "fromServer"); cookie.Expires = DateTime.Now.AddHours(1); HttpContext.Current.Response.AppendCookie(cookie); return true; } return false; } } }
using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Web; using System.Web.Http.Controllers; using System.Web.Http.ValueProviders; namespace WebApi { public class CookieValueProvider : IValueProvider { private Dictionary<string, string> _values; public CookieValueProvider(HttpActionContext actionContext) { if (actionContext == null) { throw new ArgumentNullException("actionContext"); } _values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); foreach (CookieHeaderValue cookie in actionContext.Request.Headers.GetCookies()) { foreach (CookieState state in cookie.Cookies) { _values[state.Name] = state.Value; } } } public bool ContainsPrefix(string prefix) { return _values.Keys.Contains(prefix); } public ValueProviderResult GetValue(string key) { string value; if (_values.TryGetValue(key, out value)) { return new ValueProviderResult(value, value, CultureInfo.InvariantCulture); } return null; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http.Controllers; using System.Web.Http.ValueProviders; namespace WebApi { public class CookieValueProviderFactory : ValueProviderFactory { public override IValueProvider GetValueProvider(HttpActionContext actionContext) { return new CookieValueProvider(actionContext); } } }