Welcome 微信登录

首页 / 网页编程 / ASP.NET / 深入分析ASP.NET Mvc 1.0 – 4. 使用ModelBinder绑定Action的参数

深入分析ASP.NET Mvc 1.0 – 4. 使用ModelBinder绑定Action的参数2011-03-26 博客园 Terry Sun在前一篇文章已经讲叙Controller.Execute(…)方法的执行流程中会调用 ControllerActionInvoker类的 InvokeAction(ControllerContext controllerContext, string actionName)方法,在InvokeAction(…)方法内又调用了GetParameterValues(…) 方法,这个方法为Action中的每个参数赋值,追踪到 GetParameterValues(…)方法内部 会发现其实每个参数的值是由GetParameterValue(…)返回的,观察 GetParameterValue( …)方法的源码:

protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) {
// collect all of the necessary binding properties
Type parameterType = parameterDescriptor.ParameterType;
IModelBinder binder = GetModelBinder (parameterDescriptor);
IDictionary<string, ValueProviderResult> 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
ModelName = parameterName,
ModelState = controllerContext.Controller.ViewData.ModelState,
ModelType = parameterType,
PropertyFilter = propertyFilter,
ValueProvider = valueProvider
};
object result = binder.BindModel(controllerContext, bindingContext);
return result;
}

代码的逻辑分为:

获取继承了IModelBinder接口的对象

执行IModelBinder对象的BindModel(…)方法并返回Action的参数值

继承IModelBinder接口的对象有三个类:DefaultModelBinder, FormCollectionModelBinder和HttpPostedFileBaseModelBinder

在GetParameterValue(…)方法中可以看到由GetModelBinder(parameterDescriptor) 负责返回IModelBinder对象,但他是如何确定返回哪个ModeBinder的呢?

当Action的参数类型为FormCollection时,GetParameterValue(…)方法返回 FormCollectoinModelBinder对象

当Action的参数类型为HttpPostedFileBase时,GetParameterValue(…)方法返回 HttpPostedFileBaseModelBinder对象

当Action的参数类型除了FormCollection和HttpPostedFileBase外(int, string, boolean或强类型),GetParameterValue(…)方法返回DefaultModelBinder对象, DefaultModelBinder也是最常用的ModelBinder

来深入到GetModelBinder(…)方法的内部

private IModelBinder GetModelBinder(ParameterDescriptor parameterDescriptor) {
// look on the parameter itself, then look in the global table
return parameterDescriptor.BindingInfo.Binder ?? Binders.GetBinder(parameterDescriptor.ParameterType);
}

通常情况下IModelBinder都是由 Binders.GetBinder (parameterDescriptor.ParameterType)返回, Binders属性调用ModelBinders.Binders 返回ModelBinderDictionary的静态实例,在调用 ModelBinders.Binders属性返回 ModelBinderDictionary对象之前先初始化 ModelBinderDictionary对象并将 HttpPostedFileBaseModelBinder保存到 ModelBinderDictionary对象中(代码如下),最 后其实是调用ModelBinderDictionary的GetBinder()方法返回的IModelBinder对象。

public static class ModelBinders {
private static readonly ModelBinderDictionary _binders = CreateDefaultBinderDictionary();

public static ModelBinderDictionary Binders {
get {
return _binders;
}
}

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() }
};
return binders;
}

}