快捷搜索:  as  test  1111  test aNd 8=8  test++aNd+8=8  as++aNd+8=8  as aNd 8=8

同乐城娱乐同乐城:【ASP.NET MVC教程】6、Model Binding的实现示例



在Filter和Action的履行 中说到,ControllerActionInvoker工具在InvokeAction措施中调用了GetParameters措施实现了model binding,先来看下这个措施:

protected virtual IDictionarystring, object> GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {

Dictionarystring, object> parametersDict = new Dictionarystring, object>(StringComparer.OrdinalIgnoreCase);ParameterDescriptor[] parameterDescriptors = actionDescriptor.GetParameters();

foreach (ParameterDescriptor parameterDescriptor in parameterDescriptors) {

parametersDict[parameterDescriptor.ParameterName] = GetParameterValue(controllerContext, parameterDescriptor);}

return parametersDict;}

首先经由过程actionDescriptor得到action参数的信息,这里的actionDescriptor实际上是一个ReflectedActionDescriptor,得到参数的措施自然是经由过程反射,不深入阐发了。紧接着就对每个参赛调用了GetParameterValue措施:

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

// collect all of the necessary binding propertiesType parameterType = parameterDescriptor.ParameterType;

IModelBinder binder = GetModelBinder(parameterDescriptor);IValueProvider valueProvider = controllerContext.Controller.ValueProvider;

string parameterName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;Predicatestring> propertyFilter = GetPropertyFilter(parameterDescriptor);

// finally, call into the binder

ModelBindingContext bindingContext = new ModelBindingContext() {FallbackToEmptyPrefix = (parameterDescriptor.BindingInfo.Prefix == null), // only fall back if prefix not specified

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

ModelState = controllerContext.Controller.ViewData.Mo同乐城娱乐同乐城delState,PropertyFilter = propertyFilter,

ValueProvider = valueProvider};

object result = binder.BindModel(controllerContext, bindingContext);return result ?? parameterDescriptor.DefaultValue;

}

这个措施中完成了几件事,首先是得到Model Binder,其次是得到Value Provider,再得到Property Filter,终极把这些信息组成ModelBindingContext,交给binder的BindModel措施实现绑定。先看若何得到Model Binder和Value Provider,这里将是扩展model binding的动手点。GetModelBinder措施如下:

private IModelBinder GetModelBinder(ParameterDescriptor parameterDescriptor) {

// look on the parameter itself, then look in the global tablereturn parameterDescriptor.BindingInfo.Binder ?? Binders.GetBinder(parameterDescriptor.ParameterType);

}

假如经由过程action的参数的Atrribute阐清楚明了采纳什么binder的话就优先应用这个binder,否则从全局binder中查找。这里Binders是一个ModelBinderDictionary工具,其初始化是在ModelBinders类中的CreateDefaultBinderDictionary措施:

private static ModelBinderDictionary CreateDefaultBinderDictionary() {

// We can't add a binder to the HttpPostedFileBase type as an attribute, so we'll just// prepopulate the dictionary as a convenience to users.

ModelBinderDictionary binders = new ModelBinderDictionary() {{ typeof(HttpPostedFileBase), new HttpPostedFileBaseModelBinder() },

{ typeof(byte[]), new ByteArrayModelBinder() },{ typeof(Binary), new LinqBinaryModelBinder() }

};return binders;

}

在这里筹备了几个默认的ModelBinder.筹备事情完成之后,看真正的GetBinder措施,这个措施颠末几个重载的措施之后,终极调用的是如下的措施:

return GetBinder(modelType, (fallbackToDefault) ? DefaultBinder : null);

这里fallbackToDefault是true,DefaultBinder便是一个DefaultModelBinder工具,这个措施的实现如下:

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 binderIModelBinder binder = _modelBinderProviders.GetBinder(modelType);

if (binder != null) {return binder;

}if (_innerDicti同乐城娱乐同乐城onary.TryGetValue(modelType, out binder)) {

return binder;}

binder = ModelBinders.GetBinderFromAttributes(modelType,() => String.Format(CultureInfo.CurrentCultu同乐城娱乐同乐城re, MvcResources.ModelBinderDictionary_MultipleAttributes, modelType.FullName));

return binder ?? fallbackBinder;}

加上注释的赞助,很轻易理解获取一个类型对应的model binder的历程是若何的。首先是经由过程IModelBinderProvider来查找,这里的modelBinderProviders在默认环境下便是ModelBinderProviders.BinderProviders属性,这是ModelBinderProviderCollection类型的工具。我们要应用自定义的model binder,一个措施便是实现一个IModelBinderProivder,并且经由过程ModelBinderProviders.BinderProviders.Add措施注册到全局的provider表中。第二个道路是经由过程现有的binder表,这里的_innerDictionary是一个Dictionary类型的工具,也便是ModelBinderDictionary实际存储数据的地方,ModelBinders.Binders.Add措施就会直接往这个dictionary中添加数据。第三个道路是经由过程待绑定类型的Attribute来加载binder。着末,假如上面的道路都没有找到binder,那么就用默认的DefaultModelBinder,大年夜多半时刻这个DefaultModelBinder已经足够强大年夜。暂时先跳过这个DefaultModelBinder的实现,再回到GetParameterValue中,当获得相宜的model binder之后还必要得到value provider:

IValueProvider valueProvider = controllerContext.Controller.ValueProvider;

这里的ValueProvider是定义在ControllerBase类型中的:

public IValueProvider ValueProvider {

get {if (_valueProvider == null) {

_valueProvider = ValueProviderFactories.Factories.GetValueProvider(ControllerContext);}

return _valueProvider;}

set {_valueProvider = value;

}}

下面来看下 ValueProviderFactories的实现:

public static class ValueProviderFactories {

private static readonly ValueProviderFactoryCollection _factories = new ValueProviderFactoryCollection() {

new ChildActionValueProviderFactory(),new Fo同乐城娱乐同乐城rmValueProviderFactory(),

new JsonValueProviderFactory(),new RouteDataValueProviderFactory(),

new QueryStringValueProviderFactory(),new HttpFileCollectionValueProviderFactory(),

};

public static ValueProviderFactoryCollection Factories {get {

return _factories;}

} }

这个类初始化了一系列默认的ValueProviderFactory。再看下GetValueProvider(ControllerContext) 这个措施的实现:

public IValueProvider GetValueProvider(ControllerContext controllerContext) {

var valueProviders = from factory in _serviceResolver.Currentlet同乐城娱乐同乐城 valueProvider = factory.GetValueProvider(controllerContext)

where valueProvider != nullselect valueProvider;

return new ValueProviderCollection(valueProviders.ToList());

}

这里的做法是返回所有的能够找到的value provider,再将其组合成一个ValueProviderCollection.再看下ValueProviderCollection的关键措施的实现:

public virtual ValueProviderResult GetValue(string key) {

return GetValue(key, skipValidation: false); }

public virtual ValueProviderResult GetValue(string key, bool skipValidation) {

return (from provider in thislet result = GetValueFromProvider(provider, key, skipValidation)

where result != nullselect result).FirstOrDefault();

}

internal static ValueProviderResult GetValueFromProvider(IValueProvider provider, string key, bool skipValidation) {// Since IUnvalidatedValueProvider is a superset of IValueProvider, it's always OK to use the

// IUnvalidatedValueProvider-supplied members if they're present. Otherwise just call the// normal IValueProvider members.

IUnvalidatedValueProvider unvalidatedProvider = provider as IUnvalidatedValueProvider;

return (unvalidatedProvider != null) ? unvalidatedProvider.GetValue(key, skipValidation) : provider.GetValue(key); }

这个措施返回的是第一个能够找到value的ValueProvider返回的值。附上函数调用图:

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

您可能还会对下面的文章感兴趣: