• mvc源码解读(16)数据绑定组件ModelBinder之ModelBinderProviders


        在上一篇中我们讲到了应用在Action方法参数上述的ModelBinder,源码具体分析到:

     private IModelBinder GetModelBinder(ParameterDescriptor parameterDescriptor) {
                return parameterDescriptor.BindingInfo.Binder ?? Binders.GetBinder(parameterDescriptor.ParameterType);
            }

    我们已经讲了ReflectedParameterBindingInfo的Binder属性,假如它为空的话,则根据参数类型来获取ModelBinder,GetBinder方法的具体实现是在ModelBinderDictionary类里面:

     public IModelBinder GetBinder(Type modelType) {
                return GetBinder(modelType, true /* fallbackToDefault */);
            }

    这个方法最终调用的又是GetBinder的一个重载方法,这个方法的第二个参数是一个bool类型,具体实现如下:

    public virtual IModelBinder GetBinder(Type modelType, bool fallbackToDefault) {
                if (modelType == null) {
                    throw new ArgumentNullException("modelType");
                }
                //fallbackToDefault表示是否启用默认的DefaultModelBinder.
                return GetBinder(modelType, (fallbackToDefault) ? DefaultBinder : null);
            }

     我们可以发现GetBinder的第二个参数fallbackToDefault为true的时候表示启用mvc默认的DefaultModelBinder。该方法里面调用的又是GetBinder的另外一个重载方法,该方法也是在ModelBinderDictionary类里面定义的,方法具体实现如下:

    private IModelBinder GetBinder(Type modelType, IModelBinder fallbackBinder) {

                 // Try to look up a binder for this type. We use this order of precedence:            

                 // 1. Binder returned from provider            

                // 2. Binder registered in the global table            

               // 3. Binder attribute defined on the type            

              // 4. Supplied fallback binder

                IModelBinder binder = _modelBinderProviders.GetBinder(modelType);            

                if (binder != null) {return binder;}

                if (_innerDictionary.TryGetValue(modelType, out binder)) {return binder; }

                binder = ModelBinders.GetBinderFromAttributes(modelType, () => String.Format(CultureInfo.CurrentCulture, MvcResources.ModelBinderDictionary_MultipleAttributes, modelType.FullName));

                return binder ?? fallbackBinder;        

    }

    上面列举了获取ModelBinder的四种优先顺序,我们先来看第一个优先选择的ModelBinder,是从provider里面获取的ModelBinder,具体实现是在类ModelBinderProviderCollection里面:

     public IModelBinder GetBinder(Type modelType) {

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

                var modelBinders = from providers in CombinedItems                               

                                             let modelBinder = providers.GetBinder(modelType)                               

                                             where modelBinder != null                               

                                             select modelBinder;

                return modelBinders.FirstOrDefault();        

    }

    对于类ModelBinderProviderCollection顾名思义我们理解为是ModelBinderProvider的一个集合,里面包括了当前应用的ModelBinderProvider列表,上面的红色代码中GetBinder方法实现的是接口IModelBinderProvider里面的GetBinder,该方法具体定义如下:

     public interface IModelBinderProvider {
            IModelBinder GetBinder(Type modelType);
        }

    但是mvc中并没有提供实现该接口的类,我在看源码的时候一直卡在这里想不通,知道看到了ModelBinderProviders这个类,我才知道了它的用意,这个先卖个关子,我们直接看ModelBinderProviders类里面的成员:

     public static class ModelBinderProviders {

            private readonly static ModelBinderProviderCollection _binderProviders = new ModelBinderProviderCollection {};

            public static ModelBinderProviderCollection BinderProviders {

                           get {return _binderProviders;}        

            }    

    }

    BinderProviders属性就是对ModelBinderProviderCollection的封装,而我们可以看到ModelBinderProviderCollection是继承自 Collection<IModelBinderProvider>,定义如下:

    public class ModelBinderProviderCollection : Collection<IModelBinderProvider>

    那既然mvc没有提供实现IModelBinderProvider的类,那ModelBinderProviders的属性BinderProviders表示的ModelBinderProvider列表什么时候被调用的呢?看过源码我们发现最终是被ModelBinderDictionary来使用,我们来看ModelBinderDictionary的一些成员:

    private IModelBinder _defaultBinder;
    private readonly Dictionary<Type, IModelBinder> _innerDictionary = new Dictionary<Type, IModelBinder>();
    private ModelBinderProviderCollection _modelBinderProviders;

    里面包含了ModelBinderProviderCollection类的实例,那这个实例是什么时候被初始化的呢?初始化之前我们知道这个集合里里面肯定是没有数据,因此我们在mvc应用程序的全局文件Global.asax里面的Application_Start()里面进行初始化的工作。如下所示:

       ModelBinderProviders.BinderProviders.Add(******);

    这样的话从provider就获取到了ModelBinder。

  • 相关阅读:
    golang 实现生产者消费者模式(转)
    ssh设置免密登录后登录仍需密码可能的原因,以及 ssh 出问题或的调试方法
    http 请求 Cros 跨域问题记录(转)
    问题解决——SSH时出现WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!(转)
    Git撤销本地commit(转)
    golang project 不显示文件夹 或者某个包明明能 import 但就是 import 不进来,提示Unresolved reference
    Qt6.2.4 qml 实现登录注册及显示详情demo
    Qt6.2.4 qml 实现文件选择与内容读取
    【转载】Qt6.2.4 qml ChartView 实现饼状图与问题解决
    【转载】AntvX6 流程图 demo 基于原生 js 支持导入与导出数据
  • 原文地址:https://www.cnblogs.com/ghhlyy/p/2941171.html
Copyright © 2020-2023  润新知