首页 > 代码库 > ModelBinder

ModelBinder

MVC Form表单的value就会自动匹配到Action的参数中,是如何实现的呢?

通过 反编译System.Web.Mvc.dll, 从Controller入手,会发现Controller中的执行核心ExcuteCore()中会InvokeAction

技术分享

这里ActionInvoker是一个ControllerActionInvoker对象中调用了GetPrameterValues方法

技术分享

ActionDescriptor的作用是对Action方法的元数据的描述,通过ActionDescriptor可以获取action的参数列表。

遍历参数列表为参数列表和表单数据做binding。

技术分享

这里Modelbinder出现了,初始化Modelbinding上下文

ModelMetaData: model的显示和验证信息。

ModelName:model名称,如果有前缀的话就是前缀名(User.Name),没有的话就是参数名(User or Name)

ModelState: 提示model的错误信息,验证通过IsValid = ture

PropertyFilter:ParameterBindingInfo参数绑定的信息,如:有没有前缀,有没有需要include或exclude binding的数据。

关键方法ModelBinder.BindModel.

MVC有默认的ModelBinder:DefaultModelBinder 实现了IModelBinder接口的BindModel方法即可。(所以我们如果想实现自己的ModelBinder,可以实现IModelBinder接口)BindModel中有两种SimpleBind ,ComplexBind

技术分享

 

自定义MyModelBinder:

技术分享
public class MyModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            return GetModel(bindingContext.ValueProvider, bindingContext.ModelName, bindingContext.ModelType);
        }
        public object GetModel(IValueProvider valueProvider, string modelName, Type modelType)
        {

            ModelMetadata modelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => null, modelType);
            //如果绑定的类型是简单类型
            if (!modelMetadata.IsComplexType)
            {
                return valueProvider.GetValue(modelName).ConvertTo(modelType);
            }
            object model = Activator.CreateInstance(modelType);
            //如果是复杂类型
            //前台表单标签的name属性的值有modelName的前缀
            if (valueProvider.ContainsPrefix(modelName))
            {
                foreach (PropertyDescriptor porperty in TypeDescriptor.GetProperties(modelType))
                {

                    string strkey = modelName + "." + porperty.Name;
                    if (HttpContext.Current.Request.Form.AllKeys.Contains<string>(strkey))
                        porperty.SetValue(model, valueProvider.GetValue(strkey).ConvertTo(porperty.PropertyType));
                }
            }
            //不包含前缀,但是标签的name属性的值等于绑定类的属性的名字
            else
            {
                foreach (PropertyDescriptor porperty in TypeDescriptor.GetProperties(modelType))
                {
                    string strkey = porperty.Name;
                    if (HttpContext.Current.Request.Form.AllKeys.Contains<string>(strkey))
                        porperty.SetValue(model, valueProvider.GetValue(strkey).ConvertTo(porperty.PropertyType));
                }

            }
            return model;
        }


    }
View Code
 public ActionResult ModelBinder([ModelBinder(typeof(MyModelBinder))]User User)

 

ModelBinder