首页 > 代码库 > MVC5-10 ModleBinder那点事

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...               }        }    }

MVC5-10 ModleBinder那点事