Asp.net MVC源码分析--获取ModelBinder的优先级
在asp.net mvc 框架中我们可以对System.Web.Mvc.Binders 进行扩展我们自定义的binder 类型,但是同时它还有一些其它的方法可以实现自定义的model binder.而且mvc在使用的时候还有一些策略,现分析如下:
获取ModelBinder 对象的入口方法是GetParameterValue, 其中
IModelBinder binder = GetModelBinder(parameterDescriptor);
这一句代码决定了ModelBinder 的使用策略。
System.Web.Mvc.ControllerActionInvoker
protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) {
// collect all of the necessary binding properties
Type parameterType = parameterDescriptor.ParameterType;
//Hey 请过来获取binder 的入口在这里,csdn 代段没法加高亮,垃极啊~!
IModelBinder binder = GetModelBinder(parameterDescriptor);
IValueProvider valueProvider = controllerContext.Controller.ValueProvider;
string parameterName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;
Predicate<string> 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.ModelState,
PropertyFilter = propertyFilter,
ValueProvider = valueProvider
};
object result = binder.BindModel(controllerContext, bindingContext);
return result ?? parameterDescriptor.DefaultValue;
}
private IModelBinder GetModelBinder(ParameterDescriptor parameterDescriptor) {
// look on the parameter itself, then look in the global table
return parameterDescriptor.BindingInfo.Binder ?? Binders.GetBinder(parameterDescriptor.ParameterType);
}
这里优先从parameterDescriptor.BindingInfo中得到IModelBinder, 接下来我们看一下怎么从parameterDescriptor中获取binder
首先找到ReflectedActionDescriptor对象,可以看到在GetParameters方法中生成了ReflectedParameterDescriptor 对象,
System.Web.Mvc.ReflectedActionDescriptor
public override ParameterDescriptor[] GetParameters() {
ParameterDescriptor[] parameters = LazilyFetchParametersCollection();
// need to clone array so that user modifications aren't accidentally stored
return (ParameterDescriptor[])parameters.Clone();
}
view plain
private ParameterDescriptor[] LazilyFetchParametersCollection() {
return DescriptorUtil.LazilyFetchOrCreateDescriptors<ParameterInfo, ParameterDescriptor>(
ref _parametersCache /* cacheLocation */,
MethodInfo.GetParameters /* initializer */,
parameterInfo => new ReflectedParameterDescriptor(parameterInfo, this) /* converter */);
}
这个对象中调用了ModelBinders.GetBinderFromAttributes方法来获取binder
ReflectedParameterDescriptor -> ReflectedParameterBindingInfo
public override IModelBinder Binder {
get {
IModelBinder binder = ModelBinders.GetBinderFromAttributes(_parameterInfo,
() => String.Format(CultureInfo.CurrentCulture, MvcResources.ReflectedParameterBindingInfo_MultipleConverterAttributes,
_parameterInfo.Name, _parameterInfo.Member));
return binder;
}
}
System.Web.Mvc.ModelBinders
internal static IModelBinder GetBinderFromAttributes(ICustomAttributeProvider element, Func<string>
errorMessageAccessor) {
CustomModelBinderAttribute[] attrs = (CustomModelBinderAttribute[])element.
GetCustomAttributes(typeof(CustomModelBinderAttribute),
true /* inherit */);
return GetBinderFromAttributesImpl(attrs, errorMessageAccessor);
}
接下来我们看
return parameterDescriptor.BindingInfo.Binder ?? Binders.GetBinder(parameterDescriptor.ParameterType);
语句后面的的分支.
System.Web.Mvc.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 =
补充:Web开发 , ASP.Net ,