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类型的字典类型作为数据源;

 

posted @ 2015-12-18 17:15  飞蛾扑火  阅读(405)  评论(0编辑  收藏  举报