• MVC框架中的值提供机制(三)


        在MVC框架中NameValueCollectionValueProvider采用一个NameValueCollection作为数据源,DictionnaryValueProvider的数据源类型自然就是一个Dictionnary。  

         NameValueCollection和Dictionnary都是一个键值对的集合,它们之间的不同之处在NameValueCollection运行元素具有相同的Key,Dictionnary却要求元素的Key具有唯一性。

    DictionnaryValueProvider

         在MVC框架默认的值提供程序中,ChildActionValueProvider,RouteDataValueProvider,HttpFileCollectionValueProvider等值提供程序都继承了DictionaryValueProvider类;

     public class DictionaryValueProvider<TValue> : IValueProvider, IEnumerableValueProvider
     {
            private PrefixContainer _prefixContainer;
            private readonly Dictionary<string, ValueProviderResult> _values = new Dictionary<string, ValueProviderResult>(StringComparer.OrdinalIgnoreCase);
    
            public DictionaryValueProvider(IDictionary<string, TValue> dictionary, CultureInfo culture)
            {
                if (dictionary == null)
                {
                    throw new ArgumentNullException("dictionary");
                }
    
                foreach (KeyValuePair<string, TValue> entry in dictionary)
                {
                    object rawValue = entry.Value;
                    string attemptedValue = Convert.ToString(rawValue, culture);
                    _values[entry.Key] = new ValueProviderResult(rawValue, attemptedValue, culture);
                }
            }
    }

       在DictionaryValueProvider的构造函数中接收一个key-value的字典类型,在函数内部逐个遍历这个字典类型,将每一项转换为ValueProviderResult类型,并以key-value的形式存储在Dictionary<string, ValueProviderResult> _values 中,在数据的查询都是在这个value字典里面进行查询;

       DictionaryValueProvider类继承了IValueProvider和IEnumerableValueProvider接口;

       IValueProvider:声明GetValue方法和ContainsPrefix方法,前者根据key获得对应的Value,这个key有可能是带前缀的;后者是判断是否有给定前缀的key。

       IEnumerableValueProvider:继承IValueProvider。针对目标类型为集合(Collection)的数据提供,生命了GetKeysFromPrefix方法,返回容器中具有指定前缀的Key,这个过程默认是需要验证的。

       

     private PrefixContainer PrefixContainer
     {
        get
         {
           if (_prefixContainer == null)
           {
               _prefixContainer = new PrefixContainer(_values.Keys);
           }
           return _prefixContainer;
          }
      }
    public virtual bool ContainsPrefix(string prefix) { return PrefixContainer.ContainsPrefix(prefix); } public virtual ValueProviderResult GetValue(string key) { if (key == null) { throw new ArgumentNullException("key"); } ValueProviderResult valueProviderResult; _values.TryGetValue(key, out valueProviderResult); return valueProviderResult; } public virtual IDictionary<string, string> GetKeysFromPrefix(string prefix) { return PrefixContainer.GetKeysFromPrefix(prefix); }

    DictionaryValueProvider类中的ContainsPrefix方法和GetKeysFromPrefix方法实际上是调用的PrefixContainer中的对应方法,在MVC框架中默认为PrefixContainer类;而GetValue根据key查找value字典的数据;因此DictionaryValueProvider类的作用实际上是做数据加工的作用,对应数据进行筛选的数据源来源于外部,通过构造方法的参数传入;

    ChildActionValueProvider

    public sealed class ChildActionValueProvider : DictionaryValueProvider<object>
    {
       private static string _childActionValuesKey = Guid.NewGuid().ToString();
       public ChildActionValueProvider(ControllerContext controllerContext)
                : base(controllerContext.RouteData.Values, CultureInfo.InvariantCulture)
       {
       }
    }

          ChildActionValueProvider专门服务于针对子Action方法参数的Model绑定。ChildActionValueProvider类在创建的过程中会把controllerContext.RouteData.Values坐位数据源传入到DictionaryValueProvider类中;但是在ChildActionValueProvider类中重写了DictionaryValueProvider类的GetValue方法;

     private static string _childActionValuesKey = Guid.NewGuid().ToString();
     public override ValueProviderResult GetValue(string key)
     {
        if (key == null)
        {
           throw new ArgumentNullException("key");
        }
        ValueProviderResult explicitValues = base.GetValue(ChildActionValuesKey);
        if (explicitValues != null)
        {
    DictionaryValueProvider
    <object> rawExplicitValues = explicitValues.RawValue as DictionaryValueProvider<object>; if (rawExplicitValues != null) { return rawExplicitValues.GetValue(key); } } return null; }

       当调用ChildActionValueProvider的GetValue方法获取指定Key的值时,实际上并不会直接根据指定的Key去获取对应的值,而是根据通过其静态字段_childActionValuesKey值去获取对应的DictionaryValueProvider<object>对象。然后再调用该对象的GetValue根据指定的Key去获得相应的值。

      RouteDataValueProvider

     public sealed class RouteDataValueProvider : DictionaryValueProvider<object>
     {
        public RouteDataValueProvider(ControllerContext controllerContext)
                : base(controllerContext.RouteData.Values, CultureInfo.InvariantCulture)
            {
            }
     }

    RouteDataValueProvider类是将路由数据(controllerContext.RouteData.Values)做为数据源;

    HttpFileCollectionValueProvider

     public sealed class HttpFileCollectionValueProvider : DictionaryValueProvider<HttpPostedFileBase[]>
     {
        private static readonly Dictionary<string, HttpPostedFileBase[]> _emptyDictionary = new Dictionary<string, HttpPostedFileBase[]>();
    
        public HttpFileCollectionValueProvider(ControllerContext controllerContext)
                : base(GetHttpPostedFileDictionary(controllerContext), CultureInfo.InvariantCulture)
        {
        }
    private static Dictionary<string, HttpPostedFileBase[]> GetHttpPostedFileDictionary(ControllerContext controllerContext)
        {
          HttpFileCollectionBase files = controllerContext.HttpContext.Request.Files;
            // fast-track common case of no files
           if (files.Count == 0)
           {
              return _emptyDictionary;
           }
           List<KeyValuePair<string, HttpPostedFileBase>> mapping = new List<KeyValuePair<string, HttpPostedFileBase>>();
           string[] allKeys = files.AllKeys;
           for (int i = 0; i < files.Count; i++)
           {
               string key = allKeys[i];
               if (key != null)
               {
                  HttpPostedFileBase file = HttpPostedFileBaseModelBinder.ChooseFileOrNull(files[i]);
                  mapping.Add(new KeyValuePair<string, HttpPostedFileBase>(key, file));
                }
           }
            var grouped = mapping.GroupBy(el => el.Key, el => el.Value, StringComparer.OrdinalIgnoreCase);
            return grouped.ToDictionary(g => g.Key, g => g.ToArray(), StringComparer.OrdinalIgnoreCase);
      }

          HttpFileCollectionValueProvider类是文件上传的的值提供程序,在HTTP请求的HttpRequestBase对象中,上传文件通过只读属性Files表示;在构造函数中通过GetHttpPostedFileDictionary方法创建一个key为文件名Value为HttpPostedFileBase类型的字典类型作为数据源;

  • 相关阅读:
    day02-数据库操作
    day01-MySQL介绍
    3-socketserver
    1-多线程与多进程
    keyword模块
    math模块
    查看进程pid与ppid
    开启进程的两种方式
    进程理论
    进程
  • 原文地址:https://www.cnblogs.com/h20064528/p/5057655.html
Copyright © 2020-2023  润新知