ASP.NET MVC 控制器激活(二)
前言
在之前的篇幅中,用文字和图像来表示了控制器的激活过程,描述的角度都是从框架默认实现的角度去进行描述的,这样也使得大家都可以清楚的知道激活的过程以及其中涉及到的对象模型,今天的篇幅就是在激活的过程中,框架提供了哪些可注入点,站在一个使用者的角度来进行描述。
激活控制器-注入点入口
如上图,这是上个篇幅中描述的控制器激活过程图,这里引用过来是怕有的朋友忘记了前面的所说和没看过前面篇幅的朋友。
就从默认控制器工厂的实现来看,在CreateController()方法中,通过GetControllerType()方法来获取控制器类型(Type),然后传递到GetControllerInstance()方法中,通过其中的实现来完成根据控制器类型(Type)到IController的生成。而在后续的注入点也是在GetControllerInstance()方法实现中来进行注入的,GetControllerInstance()方法即是整个控制器激活过程的入口点。
IoC示例
既然说到了动态注入,想必就要用到IoC框架了,在MVC学前篇中提到过Ninject的使用,下面这个示例便是依赖于Ninject的来做的演示:
1
2
3
4
5
6
7
8
|
1
/// <summary>
2
/// 产品实体类
3
/// </summary>
4
public
class
Product
5 {
6
public
string
ID {
get
;
set
; }
7
public
string
Name {
get
;
set
; }
8 }
|
定义一个数据实体类没什么好说的,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
1
/// <summary>
2
/// 抽象数据提取库
3
/// </summary>
4
public
interface
IDataStandard
5 {
6 List<Product> GetProducts();
7 }
8
/// <summary>
9
/// 默认实现--数据提取库
10
/// </summary>
11
public
class
DataProvide : IDataStandard
12 {
13
14
public
List<Product> GetProducts()
15 {
16 List<Product> products =
new
List<Product>()
17 {
18
new
Product(){ ID=
"1"
,Name=
"name1"
},
19
new
Product(){ID=
"2"
,Name=
"name2"
},
20
new
Product(){ID=
"3"
,Name=
"name3"
}
21 };
22
return
products;
23 }
24 }
|
这里定义的一个是抽象的数据提取库,和一个默认的实现作为演示用于提供数据用的。
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
|
1
/// <summary>
2
/// 抽象数据调用
3
/// </summary>
4
public
interface
IDataCall
5 {
6
void
WriterToMonitor();
7 }
8
9
/// <summary>
10
/// 默认的数据调用实现
11
/// </summary>
12
public
class
DefultDataCall:IDataCall
13 {
14
private
IDataStandard _DataStandard;
15
16
public
DefultDataCall(IDataStandard dataStandard)
//使用构造函数方式注入 通过Ninject框架实现
17 {
18 _DataStandard = dataStandard;
19 }
20
21
public
void
WriterToMonitor()
22 {
23
foreach
(
var
data
in
_DataStandard.GetProducts())
24 {
25 Console.WriteLine(
"Prodcut ID:"
+ data.ID +
" Name:"
+ data.Name);
26 }
27 }
28 }
|
这里定义的是抽象的数据调用和默认的实现,我们现在要做的就是通过IoC框架来让调用客户端对数据调用和数据提取解耦,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
1
class
Program
2 {
3
static
void
Main(
string
[] args)
4 {
5 IKernel ninject =
new
StandardKernel();
6 ninject.Bind<IDataStandard>().To<DataProvide>();
7 IDataCall dataCall = ninject.Get(
typeof
(DefultDataCall))
as
IDataCall;
8
if
(dataCall !=
null
)
9 {
10 dataCall.WriterToMonitor();
11 }
12
13 Console.ReadLine();
14 }
15 }
|
运行这段代码:
很简单明了的一个示例,在MVC的项目中也是这样运行的。
MVC项目中的运用
在上面的章节里说过,入口点在protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType);方法中,我们只需要实现一个默认的控制器工厂类型,并且重写一下这个方法,因为我们已经可以在重写的方法中获取到控制器的类型了,有了它就可以按照IoC示例中的那样来进行其它对象到控制器的一个动态注入。
我们先要定义一个控制器,并且要让它对上述示例中的抽象提取库依赖,采取构造函数式注入(依赖)。
看一下示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
1
public
class
IoCDemoController : Controller
2 {
3
//
4
// GET: /IoCDemo/
5
6
private
IDataStandard _DataStandard;
7
8
public
IoCDemoController(IDataStandard dataStandard)
9 {
10 _DataStandard = dataStandard;
11 }
12
13
public
ActionResult Index()
14 {
15
return
View(_DataStandard.GetProducts());
16 }
17 }
|
在Index方法上右键,点击添加视图:
点击添加,并且在视图中输入如下代码:
1
2
3
4
5
6
7
8
9
|
@model IEnumerable<
ConsoleApplication2.Product
>
@{
ViewBag.Title = "Index";
}
<
h2
>Index</
h2
>
@foreach (var item in Model)
{
<
h3
>ID: @item.ID Name:@item.Name</
h3
>
}
|
再把Global.asax文件中的路由设置修改一下:
1
2
3
4
5
|
1 routes.MapRoute(
2
"Default"
,
// 路由名称
3
"{controller}/{action}/{id}"
,
// 带有参数的 URL
4
new
{ controller =
"IoCDemo"
, action =
"Index"
, id = UrlParameter.Optional }
// 参数默认值
5 );
|
这个时候准备工作都做好,可是控制器中所用的数据哪里来呢?从我们默认实现的控制器工厂中来:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
1
public
class
NinjectControllerFactory :DefaultControllerFactory
2 {
3
private
IKernel _NinjectKernel;
4
5
public
NinjectControllerFactory()
6 {
7 _NinjectKernel =
new
StandardKernel();
8 _NinjectKernel.Bind<IDataStandard>().To<DataProvide>();
9 }
10
11
protected
override
IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
12 {
13 IController controller = _NinjectKernel.Get(controllerType)
as
IController;
14
if
(controller !=
null
)
15 {
16
return
controller;
17 }
18
return
null
;
19 }
20
21 }
|
按照上面章节中的样式,在NinjectControllerFactory中事先绑定数据类型,等到系统执行需要用到控制器的时候会通过Ninject框架来讲数据动态的注入到控制器中。
最后还要设置一项:
在Global.asax文件中的Application_Start()方法中要把我们默认的实现的控制器工厂设置到MVC框架中,
1
2
3
4
5
6
7
8
|
1
protected
void
Application_Start()
2 {
3 AreaRegistration.RegisterAllAreas();
4
5 RegisterGlobalFilters(GlobalFilters.Filters);
6 RegisterRoutes(RouteTable.Routes);
7 ControllerBuilder.Current.SetControllerFactory(
new
NinjectControllerFactory());
8 }
|
添加上代码的最后一句。现在我们就可以来看一下最终效果了。
本篇就讲到这里,会在下个篇幅中继续讲解其他的注入点。
本文转自jinyuan0829 51CTO博客,原文链接:http://blog.51cto.com/jinyuan/1425165,如需转载请自行联系原作者