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

时间:2023-03-09 00:07:36
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 == )
{
return _emptyDictionary;
}
List<KeyValuePair<string, HttpPostedFileBase>> mapping = new List<KeyValuePair<string, HttpPostedFileBase>>();
string[] allKeys = files.AllKeys;
for (int i = ; 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类型的字典类型作为数据源;

相关文章