mvc源码解读(15)-数据绑定组件ModelBinder之ModelBinderAttribute

       我们继续我们MVC3源码的分析,我们在讲到MVC的过滤器的之前,我们讲到了Controller,Action和Parameter对应的描述对象ControllerDescriptor,ActionDescriptor,ParameterDescriptor,这三个对象中包含着控制器,方法,方法参数的一些相关信息,我们分析到类ControllerActionInvoker里面的InvokeAction方法里面的这一句代码:

 //执行数据的绑定(参数的初始化)
IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor);

我们上次在介绍ParameterDescriptor的时候有说到,GetParameterValues方法里面最终又调用了GetParameterValue方法并返回由GetParameterValue返回的数组对象parametersDict,因此我们来看GetParameterValue的具体实现:

 //真正数据绑定的核心        

protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) {                       

Type parameterType = parameterDescriptor.ParameterType;            

//获取binder对象            

IModelBinder binder = GetModelBinder(parameterDescriptor);            

//获取Action方法参数值            

IValueProvider valueProvider = controllerContext.Controller.ValueProvider;            

//获取Action参数名(看这个参数是否有前缀名(用于复杂类型),没有的话直接返回参数名)            

string parameterName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;

Predicate<string> propertyFilter = GetPropertyFilter(parameterDescriptor);       

ModelBindingContext bindingContext = new ModelBindingContext() {                

         FallbackToEmptyPrefix = (parameterDescriptor.BindingInfo.Prefix == null),

         //获得模型元数据。                

         ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, parameterType),                

         ModelName = parameterName,                

         //这里有验证的逻辑                

         ModelState = controllerContext.Controller.ViewData.ModelState,                

         PropertyFilter = propertyFilter,                

         ValueProvider = valueProvider            

    };

object result = binder.BindModel(controllerContext, bindingContext);            

return result ?? parameterDescriptor.DefaultValue;        

}

 我们看红色的代码,GetModelBinder方法是获取到ModelBinder的对象,我们在获取这个对象的过程可以叫做Model的绑定过程,具体来说所谓Model的绑定就是从客户端发来的请求中获取到相应的Action方法参数的一个过程,而这个过程是由一个叫ModelBinders的静态类来实现的。Model的绑定有中方式,我们先来看第一种情况,如下面GetModelBinder方法所示:

private IModelBinder GetModelBinder(ParameterDescriptor parameterDescriptor) {
            // look on the parameter itself, then look in the global table
            return parameterDescriptor.BindingInfo.Binder ?? Binders.GetBinder(parameterDescriptor.ParameterType);
        }

当parameterDescriptor.BindingInfo.Binder不为空的时候,返回的是类ModelBinder里面的GetBinderFromAttributesImpl方法的返回值,具体实现如下:

 private static IModelBinder GetBinderFromAttributesImpl(CustomModelBinderAttribute[] attrs, Func<string> errorMessageAccessor) {            

            if (attrs == null) {return null; }

            switch (attrs.Length) {                

                case 0:return null;

                case 1: IModelBinder binder = attrs[0].GetBinder();

                            return binder;

                default:string errorMessage = errorMessageAccessor();

                            throw new InvalidOperationException(errorMessage);            

             }        

}

这个方法什么时候返回的值不是为空呢?那就是当Action的方法参数上有CustomModelBinder或是ModelBinder(ModelBinderAttribute这个密封类继承自CustomModelBinderAttribute类)特性标注的时候。同时根据源码我们可以发现:Action方法中的参数只允许有一个CustomModelBinder标注特性,不能有多种类型CustomModelBinder存在。因此如果Action方法参数上有CustomModelBinder特性标注的话,就会优先选择这个Action参数的ParameterDescriptor的ModelBinder来绑定参数。ModelBinderAttribute继承了CustomModelBinderAttribute并重写了GetBinder方法,具体如下:

 public override IModelBinder GetBinder() {
            try {
                return (IModelBinder)Activator.CreateInstance(BinderType);
            }
            catch (Exception ex) {
                throw new InvalidOperationException(
                    String.Format(
                        CultureInfo.CurrentCulture,
                        MvcResources.ModelBinderAttribute_ErrorCreatingModelBinder,
                        BinderType.FullName),
                    ex);
            }
        }

里面的GetBinder方法就是根据BinderType来创建了一个ModelBinder对象。当然还有FormCollectionModelBinder,SkipBindingAttribute,DeserializeAttribute都继承了CustomModelBinderAttribute并都重写了GetBinder()。我们来看FormCollectionModelBinder表单集合的ModelBinder:

 private sealed class FormCollectionBinderAttribute : CustomModelBinderAttribute {      

            private static readonly FormCollectionModelBinder _binder = new FormCollectionModelBinder();

            public override IModelBinder GetBinder() {return _binder;} 

 

  private sealed class FormCollectionModelBinder : IModelBinder {

                     public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {                    

                             if (controllerContext == null) {throw new ArgumentNullException("controllerContext");}

                               return new FormCollection(controllerContext.Controller, () => controllerContext.HttpContext.Request.Form, () => controllerContext.HttpContext.Request.Unvalidated().Form);

                               }            

               }        

}

我们可以发现这个FormCollectionModelBinder就是从表单Form中获取到相应的Action方法的参数。

      我们来看DeserializeAttribute这个类里面的实现:

 public override IModelBinder GetBinder() {
            return new DeserializingModelBinder(Mode, Serializer);
        } 

private sealed class DeserializingModelBinder : IModelBinder {

           private readonly SerializationMode _mode;            

           private readonly MvcSerializer _serializer;

           public DeserializingModelBinder(SerializationMode mode, MvcSerializer serializer) {_mode = mode;_serializer = serializer ?? new MvcSerializer();}

           public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {

                     ValueProviderResult vpResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);                

                     if (vpResult == null) { return null;}

                     string serializedValue = (string)vpResult.ConvertTo(typeof(string));                

                     return _serializer.Deserialize(serializedValue, _mode);}

        }

这个DeserializingModelBinder就是通过反系列化之后获取到Action参数的ModelBinder。这样第一种的ModelBinder我们就获取到了。

转载于:https://www.cnblogs.com/ghhlyy/archive/2013/03/02/2939045.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值