首页 > 代码库 > 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; } }
public ActionResult ModelBinder([ModelBinder(typeof(MyModelBinder))]User User)
ModelBinder