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

 

先上前台页面

WebApi 通过ModelBinder绑定自定义参数对象

 

 

 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端代码结构

WebApi 通过ModelBinder绑定自定义参数对象

 

 

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);
        }
    }
}

  

上一篇:WebApi 重定向 Redirect


下一篇:.NET6 WebApi JSON传到前台默认变成小驼峰