在ASP.NET Model绑定系统中,用于提供数据值的ValueProvider对象通过ValueProviderFactory来创建。在ASP.NET MVC应用编程接口中,ValueProviderFactory继承自ValueProviderFactory类。本篇文章只要介绍基于ValueProviderFactory的ValueProvider的提供机制,以及如何通过自定义ValueProviderFactory实现我们需要的数据值的绑定方式。[本文已经同步到《How ASP.NET MVC Works?》中]
目录
一、ValueProviderFactory
二、ValueProviderFactory的注册
三、实例演示:创建一个自定义ValueProviderFactory
如下面的代码片断所示,ValueProviderFactory是一个抽象类,唯一的抽象方法GetValueProvider用于实现基于指定Controller上下文的ValueProvider创建。
1: public abstract class ValueProviderFactory
2: {
3: public abstract IValueProvider GetValueProvider(ControllerContext controllerContext);
4: }
下面的列表列出了定义在Model绑定系统中的6个原生的ValueProviderFactory:
ValueProviderFactory在ASP.NET MVC应用中的注册通过静态类型ValueProviderFactories实现。如下面的代码片断所示,ValueProviderFactories具有一个静态只读属性Factories返回一个表示ValueProviderFactory集合的ValueProviderFactoryCollection类型。
1: public static class ValueProviderFactories
2: {
3: public static ValueProviderFactoryCollection Factories { get; }
4: }
5:
6: public class ValueProviderFactoryCollection : Collection<ValueProviderFactory>
7: {
8: public ValueProviderFactoryCollection();
9: public ValueProviderFactoryCollection(IList<ValueProviderFactory> list);
10: public IValueProvider GetValueProvider(ControllerContext controllerContext);
11: }
ValueProviderFactoryCollection的GetValueProvider方法返回的是一个ValueProviderCollection对象,集合中的每个ValueProvider通过对应的ValueProviderFactory来创建。ValueProviderFactory在ValueProviderFactoryCollection集合中的先后次序决定了创建的ValueProvider在ValueProviderCollection中的次序,而次序决定了使用优先级。
在默认的情况下ValueProviderFactories的Factories属性表示的ValueProviderFactoryCollection包含了上面我们介绍的6种ValueProviderFactory,次序(优先级)为:ChildActionValueProviderFactory、FormValueProviderFactory、JsonValueProviderFactory、RouteDataValueProviderFactory、QueryStringValueProviderFactory和。如果具有相同的名称的请求书去同时存在于请求表单和查询字符串中,前者会被选用。
以ValueProvider为核心的值提供系统中涉及到了三类组件/类型,即用于具体实现数据值提供的ValueProvider,ValueProvider通过ValueProviderFactotry,而ValueProviderFactotry通过ValueProviderFactotries进行注册。图5-4所示的UML体现了三者之间的关系。
ASP.NET MVC提供的6种ValueProviderFactory基本上已经可以满足我们绝大部分Model绑定需求,不过对于一些比较极端的场景,我们有可能需要自定义ValueProviderFactory。作为演示,我们创建一个以HTTP请求报头集合作为数据源的自定义ValueProviderFactory。
我们将自定义的ValueProviderFactory命名为HttpHeaderValueProviderFactory。如下面的代码片断所示,HttpHeaderValueProviderFactory的定义非常简单,在重写的GetValueProvider方法中,我们将针对指定的Controller上下文得到HTTP报头集合,并借此创建NameValueCollection对象。由于作为报头名称具有“-”字符,为了与参数命名规则相匹配,我们将该字符剔除。最终创建的实际上是一个NameValueCollectionValueProvider对象。
1: public class HttpHeaderValueProviderFactory : ValueProviderFactory
2: {
3: public override IValueProvider GetValueProvider(ControllerContext controllerContext)
4: {
5: NameValueCollection requestData = new NameValueCollection();
6: var headers = controllerContext.RequestContext.HttpContext.Request.Headers;
7: foreach (string key in headers.Keys)
8: {
9: requestData.Add(key.Replace("-",""),headers[key]);
10: }
11: return new NameValueCollectionValueProvider(requestData, CultureInfo.InvariantCulture);
12: }
13: }
我们通过Visual Studio的ASP.NET MVC项目模板创建一个空Web应用,并创建一个具有如下定义的HomeController。默认的Action方法Index具有一系列的参数,从参数名称我们可以看出它们代表一些常用的HTTP报头。我们最终将代表HTTP报头的参数值呈现出来。
1: public class HomeController : Controller
2: {
3: public void Index(string connection, string accept, string acceptCharset, string acceptEncoding ,string acceptLanguage,
4: string host, string userAgent)
5: {
6: Response.Write(string.Format("{0}: {1}<br/>", "Connection", accept));
7: Response.Write(string.Format("{0}: {1}<br/>", "Accept-Charset", acceptCharset));
8: Response.Write(string.Format("{0}: {1}<br/>", "Accept Encoding", acceptEncoding));
9: Response.Write(string.Format("{0}: {1}<br/>", "Accept-Language", acceptLanguage));
10: Response.Write(string.Format("{0}: {1}<br/>", "Host", "host"));
11: Response.Write(string.Format("{0}: {1}<br/>", "User-Agent", userAgent));
12: }
13: }
然后利用Global.asax中按照如下的方式利用静态类型对我们自定义的HttpHeaderValueProviderFactory进行注册。
1: public class MvcApplication : System.Web.HttpApplication
2: {
3: //其他成员
4: protected void Application_Start()
5: {
6: //其他操作
7: ValueProviderFactories.Factories.Add(new HttpHeaderValueProviderFactory());
8: }
9: }
当我们运行该程序的时候,会在浏览器中呈现如下的输出结果,而输出的结果正是当前请求的HTTP报头列表。
1: Connection: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
2: Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
3: Accept Encoding: gzip,deflate,sdch
4: Accept-Language: en-US,en;q=0.8
5: Host: host
6: User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.