本章介绍了值提供器的作用,ASP MVC自带的5中值提供器.以及模型绑定器的作用,自定义模型绑定器并使用自定义的模型绑定器(类型上加上[ModelBinder(typeof(xx))]或者在全局模型绑定器中注册)。
补充:全局模型绑定器中注册自定义模型绑定器
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.Add(typeof(Point), new PointModelBinder());
}
值提供器
ASP .NET MVC 框架自带的若干值提供器可以提供以下数据源中的数据:
● 子操作(RenderAction)的显式值
● 表单值
● 来自 XMLHttpRequest 的 JSON 数据
● 路由值
● 查询字符串值
● 上传的文件
值提供器来自值提供器工厂,并且系统按照值提供器的注册顺序来从中搜寻数据(上面
的列表使用的是默认顺序,自顶而下)。开发人员可以编写自己的值提供器工厂和值提供器,
并且还可以将它们插入到包含在 ValueProviderFactories.Factories 中的工厂列表中。当在模
型绑定期间需要使用额外的数据源时,开发人员通常选择编写自己的值提供器工厂和值提
供器。
除了 ASP .NET MVC 本身包含的值提供器工厂以外,开发团队也在 ASP.NET MVC 3
Futures 包中包含了一些提供器工厂和值提供器,可从 http://aspnet.codeplex.com/releases/view/
58781 上下载,或者安装 NuGet 包 Mvc3Futures。具体包括以下提供器:
● Cookie 值提供器
● 服务器变量值提供器
● Session 值提供器
● TempData 值提供器
模型绑定器
1.作用
模型扩展的另一部分是模型绑定器。它们从值提供器系统中获取值,并利用获取的值创建新模型或者填充已有的模型。
模型绑定器,从值提供器中获取值。
ASP .NET MVC 中的默认模型绑定器( 为方便起见,命名为DefaultModelBinder)是一段功能非常强大的代码,它可以对传统类、集合类、列表、数组 甚至字典进行模型绑定。 但是不支持对不改变对象的模型绑定(不可变指的是只能通过构造函数初始化值的类),如果遇见不可变的对象或者类型则默认的模型绑定器就无用了。此时需要自定义模型绑定器
2. 自定义模型绑定器
实现IModelBinder接口的 BinderModel方法
object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
主要是用到ModelBindingContext类
假设要对Point类进行模型绑定(Point类只能通过构造函数进行初始化,所以只能通过自定义模型提供器)
下面是Point类代码和自定义模型绑定器代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; //IModelBinder
namespace MvcApplication1.Sample_ModelBinder { public class TestModelBinder : IModelBinder
{ public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var valueProvider = bindingContext.ValueProvider; int x = (int)valueProvider.GetValue("X").ConvertTo(typeof(int)); int y = (int)valueProvider.GetValue("Y").ConvertTo(typeof(int)); return new Point(x, y); } } public class PointModelBinder : IModelBinder
{ //public object BindModel(ControllerContext controllerContext,
//ModelBindingContext bindingContext)
//{
// var valueProvider = bindingContext.ValueProvider;
// int x = (int)valueProvider.GetValue("X").ConvertTo(typeof(int));
// int y = (int)valueProvider.GetValue("Y").ConvertTo(typeof(int));
// return new Point(x, y);
//}
private TModel Get<TModel>(ControllerContext controllerContext,ModelBindingContext bindingContext,string name) { string fullName = name; //1.modelname
if (!String.IsNullOrWhiteSpace(bindingContext.ModelName)) fullName = bindingContext.ModelName + "." + name; //2.,valueProviderResult
ValueProviderResult valueProviderResult =bindingContext.ValueProvider.GetValue(fullName); //3.modelState
ModelState modelState = new ModelState { Value = valueProviderResult }; //4.ModelstatebindingContext.ModelState
bindingContext.ModelState.Add(fullName, modelState); //5.null
ModelMetadata metadata = bindingContext.PropertyMetadata[name]; string attemptedValue = valueProviderResult.AttemptedValue; if (metadata.ConvertEmptyStringToNull&& String.IsNullOrWhiteSpace(attemptedValue)) attemptedValue = null; //6.
TModel model; bool invalidValue = false; try
{ model = (TModel)valueProviderResult.ConvertTo(typeof(TModel)); metadata.Model = model; //XX
} catch (Exception) { model = default(TModel); //int 0.boolfalse,null
metadata.Model = attemptedValue; invalidValue = true; //null
} ///
IEnumerable<ModelValidator> validators = ModelValidatorProviders.Providers.GetValidators( metadata, controllerContext ); foreach (var validator in validators) foreach (var validatorResult in
validator.Validate(bindingContext.Model)) modelState.Errors.Add(validatorResult.Message); if (invalidValue && modelState.Errors.Count == 0) modelState.Errors.Add( String.Format( "The value '{0}' is not a valid value forr {1}.", attemptedValue, metadata.GetDisplayName() ) ); return model; } public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { //1.modelname object
//
if (!String.IsNullOrEmpty(bindingContext.ModelName) && !bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName)) { if (!bindingContext.FallbackToEmptyPrefix) return null; bindingContext = new ModelBindingContext
{ ModelMetadata = bindingContext.ModelMetadata, ModelState = bindingContext.ModelState, PropertyFilter = bindingContext.PropertyFilter, ValueProvider = bindingContext.ValueProvider }; } bindingContext.ModelMetadata.Model = new Point(); return new Point(Get<int>(controllerContext, bindingContext, "X"), Get<int>(controllerContext, bindingContext, "Y")); } } [ModelBinder(typeof(PointModelBinder))] //[ModelBinder(typeof(TestModelBinder))]
public class Point
{ private int x; public int X { get { return x; } set { x = value;} //
} private int y; public int Y { get { return y;} set { y = value;} } public Point(int x, int y) { this.x = x; this.y = y; } public Point() { } } }