ASP.NET MVC Model绑定(三)
前言
看过前两篇的朋友想必对Model绑定有个大概的了解,然而MVC框架给我们提供了更高的可扩展性的提供程序编程模式,也就是本篇的主题了,会讲解一下Model绑定器提供程序的实现以及解决一下上篇遗留的问题。
第一个问题是ModelBinderProviderCollection类型的执行过程?
还有个本篇的问题就是同样的向系统上下文中注册Model绑定器和Model绑定器提供程序,哪一个优先级更高?
Model绑定
IModelBinder、自定义Model绑定器简单实现
Model绑定器在MVC框架中的位置
MVC中的默认Model绑定器生成过程
IModelBinderProvider的简单应用
IValueProvider在MVC框架中生成的位置以及过程
IValueProvider的应用场景
IValueProvider的实现之NameValueCollectionValueProvider
IModelBinderProvider的简单应用
首先我们先看一下IModelBinderProvider类型的定义,代码1-1:。
代码1-1
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
interface
IModelBinderProvider
{
// 摘要:
// 返回指定类型的模型联编程序。
//
// 参数:
// modelType:
// 模型的类型。
//
// 返回结果:
// 指定类型的模型联编程序。
IModelBinder GetBinder(Type modelType);
}
|
在代码1-1中我们看出,其中的GetBinder()方法是根据ViewModel的类型来做一些操作,最后返回Model绑定器。现在我们自定义实现一个Model绑定器提供程序代码1-2。
代码1-2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
using
System.Web.Mvc;
using
ConsoleApplication2;
namespace
MvcApplication.Infrastructure
{
public
class
MyCustomModelBinderProvider : IModelBinderProvider
{
public
IModelBinder GetBinder(Type modelType)
{
if
(modelType ==
null
)
{
throw
new
ArgumentNullException(
"modelType"
);
}
if
(modelType ==
typeof
(Customer))
{
//返回对应Customer类型的Model绑定器
}
return
null
;
}
}
}
|
在代码1-2中我们根据modelType判断是否是Customer类型,然后返回对应Customer类型的Model绑定器。为什么这里的实现是空的,因为我想把我们前面讲解过的IoC框架用起来,让Model绑定器提供程序跟Model绑定器解除耦合,想把IoC框架的应用定义在当前系统的上下文中,我们看一下代码实现,代码1-3。
代码1-3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
namespace
MvcApplication
{
public
class
MVCSystemContext
{
private
static
MVCSystemContext _MVCSystemContext;
public
static
MVCSystemContext Context
{
get
{
if
(_MVCSystemContext ==
null
)
{
_MVCSystemContext =
new
MVCSystemContext();
}
return
_MVCSystemContext;
}
}
private
ServiceContainer _serviceContainer;
private
MVCSystemContext()
{
_serviceContainer =
new
ServiceContainer();
_serviceContainer.AddService(
typeof
(NinjectController),NinjectController.Instance);
}
public
NinjectController NinjectController
{
get
{
return
(NinjectController)_serviceContainer.GetService(
typeof
(NinjectController));
}
}
}
}
|
代码1-3当中就是我定义的当前系统上下文了,只不过这个是给自己用的,上下文对象中想必是不会把所用到的所有数据或者是功能都添加在里面的,只是添加个引用而已,如代码1-3中的NinjectController属性,NinjectController属性对应的类型就是NinjectController类型,NinjectController类型的作用就是提供IoC框架的功能,我们看一下代码1-4中对于NinjectController类型的定义。
代码1-4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
using
Ninject;
namespace
MvcApplication.Infrastructure.NinjectControllerPart
{
public
class
NinjectController
{
private
static
NinjectController _Instance;
public
static
NinjectController Instance
{
get
{
return
_Instance =
new
NinjectController();
}
}
private
IKernel _ninjectKernel;
private
NinjectController()
{
_ninjectKernel =
new
StandardKernel();
}
public
void
AddKernelBind<T, U>()
where
U:T
{
_ninjectKernel.Bind<T>().To<U>();
}
public
T GetValueType<T>(Type keyType)
{
var
valueType = _ninjectKernel.Get(keyType);
return
(T)valueType;
}
}
}
|
其中对于Ninject这个IoC框架进行了一个最基础的功能封装,有的朋友可能会问为什么不公开个一个属性,何必这样多此一举,因为我对Ninject的使用也不是很熟练,对于这部分的封装我只是让其简单的公开了两个功能,一个是绑定一个是获取值,这样让这部分内容还在我的可控范围内,如果是公开属性的话,其他人的胡乱使用导致错误的话是不可控的。
切回主题,这样基础定义好了过后,我们再修改1-2中的代码,把具体实现给加上,示例代码1-5所示。
代码1-5
1
2
3
4
5
|
if
(modelType ==
typeof
(Customer))
{
//返回对应Customer类型的Model绑定器
return
MVCSystemContext.Context.NinjectController.GetValueType<IModelBinder>(
typeof
(IModelBinder));
}
|
可以看到代码1-5中,根据我们自定义上下文中的提供的IoC功能获取到绑定在IoC框架中的值,那么绑定又是在哪里呢?跟ASP.NET MVC Model绑定(一)所演示的那样,还是在项目的Global.asax文件中的MvcApplication类型的Application_Start()方法中添加如代码1-6。
代码1-6
1
2
|
MVCSystemContext.Context.NinjectController.AddKernelBind<IModelBinder, Binders.MyCustomModelBinder>();
ModelBinderProviders.BinderProviders.Add(
new
MyCustomModelBinderProvider());
|
代码1-6分别做了两个操作,先是把对应Customer类型的Model绑定器注册到了我们自定义上下文的IoC中,然后再把针对处理Customer类型的Model绑定器提供程序注册到系统中。运行结果如图1.
图1
其中涉及到所有部分的代码和ASP.NET MVC Model绑定(一)篇幅中的一样,所以这里就没有列举了。
在此我们根据上篇中最后图2所示的那样,可以判断出ModelBinderProviderCollection类型的执行过程是根据当前ParameterDescriptor类型所提供的Model类型对比我们注册到或者是系统默认提供的Model绑定器提供程序集合,如果有是针对ParameterDescriptor类型所提供的Model类型(上述示例中是Customer类型)则会有Model绑定器的返回,然后再根据Model绑定器进行Model绑定。
好了现在第一个问题解决了,来解决第二个问题。来看代码1-7所示。
代码1-7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public
class
MyCustomModelBinder:IModelBinder
{
public
object
BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
return
new
Customer()
{
CustomerID =
"010"
,
Name =
"测试人员"
,
RegistrationDate = DateTime.Now,
Address =
new
Address()
{
AddressName =
"天空之城"
}
};
}
}
public
class
MyCustomModelBinder_Test : IModelBinder
{
public
object
BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
return
new
Customer()
{
CustomerID =
"010"
,
Name =
"测试人员"
,
RegistrationDate = DateTime.Now,
Address =
new
Address()
{
AddressName =
"这里是根据Model绑定器绑定执行的Model"
}
};
}
}
|
看到代码1-7中的MyCustomModelBinder_Test 类型内部Customer类型实例内部的AddressName值已经更改的和之前的不一样了。再看一***册端的修改,示例代码1-8。
代码1-8
1
2
3
|
ModelBinders.Binders.Add(
typeof
(Customer),
new
Binders.MyCustomModelBinder_Test());
MVCSystemContext.Context.NinjectController.AddKernelBind<IModelBinder, Binders.MyCustomModelBinder>();
ModelBinderProviders.BinderProviders.Add(
new
MyCustomModelBinderProvider());
|
代码1-8中,我们把新定义的MyCustomModelBinder_Test 类型注册到了系统的Model绑定器集合中,看一下究竟是哪一个级别更高一点。
来看运行结果图2
图2
看到图2这个结果,想必已经知道了是哪个级别更高一点了。
本文转自jinyuan0829 51CTO博客,原文链接:http://blog.51cto.com/jinyuan/1432752,如需转载请自行联系原作者