MVC5-10 ModleBinder那点事
模型绑定器
之前或多或少也提到过模型绑定器,方法的形参就是由模型绑定器把参数绑定上去的,今天就说说ModuleBingder那点事
在MVC中有一个接口叫IModuleBinder
// // 摘要: // Defines the method that is required for a model binder. public interface IModelBinder { // // 摘要: // Binds the model to a value by using the specified execution context and binding // context. // // 参数: // modelBindingExecutionContext: // The execution context. // // bindingContext: // The binding context. // // 返回结果: // true if model binding is successful; otherwise, false. bool BindModel(ModelBindingExecutionContext modelBindingExecutionContext, ModelBindingContext bindingContext); }
当然,这是接口,是没有实现的,MVC给我们提供了相应的实现类。DefaultModelBinder,所有的形参都是通过它去处理的。
下面是源码,这里可以看到有两个重要的方法 BindSimpleModel、BindComplexModel 简单类型绑定与复杂类型的绑定,实际上方法是递归调用的,如果参数是对象的话,那就会创建一个对象,然后在绑定每一个属性,而绑定每一个属性的方法里又调用了BindModel方法。
public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { RuntimeHelpers.EnsureSufficientExecutionStack(); if (bindingContext == null) { throw new ArgumentNullException("bindingContext"); } bool flag = false; if (!string.IsNullOrEmpty(bindingContext.ModelName) && !bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName)) { if (!bindingContext.FallbackToEmptyPrefix) { return null; } ModelBindingContext context = new ModelBindingContext { ModelMetadata = bindingContext.ModelMetadata, ModelState = bindingContext.ModelState, PropertyFilter = bindingContext.PropertyFilter, ValueProvider = bindingContext.ValueProvider }; bindingContext = context; flag = true; } if (!flag) { bool flag2 = ShouldPerformRequestValidation(controllerContext, bindingContext); ValueProviderResult valueProviderResult = bindingContext.UnvalidatedValueProvider.GetValue(bindingContext.ModelName, !flag2); if (valueProviderResult != null) { return this.BindSimpleModel(controllerContext, bindingContext, valueProviderResult); } } if (!bindingContext.ModelMetadata.IsComplexType) { return null; } return this.BindComplexModel(controllerContext, bindingContext); }
protected virtual object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder) { object objA = propertyBinder.BindModel(controllerContext, bindingContext); if (bindingContext.ModelMetadata.ConvertEmptyStringToNull && object.Equals(objA, string.Empty)) { return null; } return objA; }
MVC是高度可替换的,如果DefaultModelBinder无法很好的实现我们的需求,那么可以写自己的ModelBinder。首先定义一个类去继承自IModelBinder实现BindModel方法,然后在Global里替换我们的MyModelBinder
public class Global : System.Web.HttpApplication { protected void Application_Start(object sender, EventArgs e) { //替换 ModelBinders.Binders.DefaultBinder = new MyModelBinder(); } public class MyModelBinder : IModelBinder { public object BindModel(ModelBindingExecutionContext modelBindingExecutionContext, ModelBindingContext bindingContext) { //Todo... } } }