一、题外话
ControllerContext
封装有了与指定的 RouteBase 和 ControllerBase 实例匹配的 HTTP 请求的信息。
二、Model绑定者
2.1相关说明
http请求中的参数绑定到Model,是由实现了IModelBinder的类来完成的。我们称这样的类叫做Model绑定者
using System; namespace System.Web.Mvc { /// <summary>Defines the methods that are required for a model binder.</summary> public interface IModelBinder { /// <summary>Binds the model to a value by using the specified controller context and binding context.</summary> /// <returns>The bound value.</returns> /// <param name="controllerContext">The controller context.</param> /// <param name="bindingContext">The binding context.</param> object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext); } }
2.2Model绑定者实现绑定的途径
1)直接在参数上绑定
using System; using System.Web; using System.Web.Mvc; namespace MVC_ST_2.Controllers { public class Person { public string Name { get; set; } public int Age { get; set; } } public class PersonModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { HttpRequestBase request = controllerContext.HttpContext.Request; var p = new Person(); p.Name = request["Name"]; p.Age =int.Parse( request["Age"]); return p; } } public class HomeController : Controller { //通过参数标记 public ActionResult Index([ModelBinder(typeof(PersonModelBinder))] Person p) { return View(); } public ActionResult Index2(Person p) { return View(); } } }
2)在model上加标记
[ModelBinder(typeof(PersonModelBinder))] public class Person { public string Name { get; set; } public int Age { get; set; } }
3)ModelBinders.Binders中注册
protected void Application_Start() { ModelBinders.Binders[typeof(Person)] = new PersonModelBinder(); }
2.3 Action中是如何调用绑定者的?
以下是
private IModelBinder GetModelBinder(ParameterDescriptor parameterDescriptor) { return parameterDescriptor.BindingInfo.Binder ?? this.Binders.GetBinder(parameterDescriptor.ParameterType); }
说明:通过参数标记的方式优先,如果没有则使用this.Binders.GetBinder(parameterDescriptor.ParameterType);
this.Binders的定义
protected internal ModelBinderDictionary Binders { get { if (this._binders == null) { this._binders = ModelBinders.Binders; } return this._binders; } set { this._binders = value; } }
从上图可以看出,最终的绑定操作交给了ModelBinderDictionary(注意了,下面会接着讲)
正好我们回到前两章讲的ControllerActionInvoker,其中的参数绑定赋值过程GetParameterValues,如何获取的过程即绑定的过程
protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) { Type parameterType = parameterDescriptor.ParameterType; IModelBinder modelBinder = this.GetModelBinder(parameterDescriptor); IValueProvider valueProvider = controllerContext.Controller.ValueProvider; string modelName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName; Predicate<string> propertyFilter = ControllerActionInvoker.GetPropertyFilter(parameterDescriptor); ModelBindingContext bindingContext = new ModelBindingContext { FallbackToEmptyPrefix = parameterDescriptor.BindingInfo.Prefix == null, ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, parameterType), ModelName = modelName, ModelState = controllerContext.Controller.ViewData.ModelState, PropertyFilter = propertyFilter, ValueProvider = valueProvider }; object obj = modelBinder.BindModel(controllerContext, bindingContext); return obj ?? parameterDescriptor.DefaultValue; }
private IModelBinder GetModelBinder(ParameterDescriptor parameterDescriptor) { return parameterDescriptor.BindingInfo.Binder ?? this.Binders.GetBinder(parameterDescriptor.ParameterType); }
this.Binders 其类型正好是ModelBinderDictionary(上面提到过),他的方法如下
public IModelBinder GetBinder(Type modelType) { return this.GetBinder(modelType, true); } /// <summary>Retrieves the model binder for the specified type or retrieves the default model binder.</summary> /// <returns>The model binder.</returns> /// <param name="modelType">The type of the model to retrieve.</param> /// <param name="fallbackToDefault">true to retrieve the default model binder.</param> /// <exception cref="T:System.ArgumentNullException">The <paramref name="modelType" /> parameter is null.</exception> public virtual IModelBinder GetBinder(Type modelType, bool fallbackToDefault) { if (modelType == null) { throw new ArgumentNullException("modelType"); } return this.GetBinder(modelType, fallbackToDefault ? this.DefaultBinder : null);
//this.DefaultBinder 是下一章我们需要讲的内容。也是整个MVC核心的默认的绑定者
} private IModelBinder GetBinder(Type modelType, IModelBinder fallbackBinder) { IModelBinder modelBinder = this._modelBinderProviders.GetBinder(modelType); if (modelBinder != null) { return modelBinder; } if (this._innerDictionary.TryGetValue(modelType, out modelBinder)) { return modelBinder; } modelBinder = ModelBinders.GetBinderFromAttributes(modelType, () => string.Format(CultureInfo.CurrentCulture, MvcResources.ModelBinderDictionary_MultipleAttributes, new object[] { modelType.FullName })); return modelBinder ?? fallbackBinder;//DefaultBinder 很多情况下,前面的几个if都不会执行,所以使用系统默认的绑定者 }