深入了解ASP.NET MVC5的Controller核心原理及扩展

本文介绍一下ASP.NET mvc中与Controller相关的高级特性,下图展示了一个MVC请求从接收到响应的过程要经历的组件的流程。

下面我们主要就来谈谈ASP.NET MVC5中的Controller Factory和Action Invoker。这两个组件通过名字也能够知道这它们的用途。

controller factory主要是用来创建Contoller的实例,而action invoker是用来查找并调用一个Contoller类中的Action方法。MVC框架本自己就已经我们实现了这两个组件,下面我们就分别举例说明一下如何在ASP.NET MVC5中,自己实现一个Controller Factory、Action Invoker,并介绍一下使用内置组件Controller Factory、Action Invoker的方法。

一、创建一个自定义的Controller Factory

对于ASP.NET MVC中的大多数类或组件,我们想要真正的搞懂它,最好的方式就是继承对应的接口或抽象类,然后自己写一个它的实现类。同理要了解Controller Factory是怎么创建一个Controller实例的我们也可以自己写一个Controller Factory我类,所有的Controller Factory都使用了接口IControllerFactory。

首先,我们来看看IControllerFactory在MVC框架中是怎么定义的:

 
  1. using System.Web.Routing;
  2. using System.Web.SessionState;
  3. namespace System.Web.Mvc {
  4. public interface IControllerFactory {
  5. IController CreateController(RequestContext requestContext,
  6. string controllerName);
  7. SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext,
  8. string controllerName);
  9. void ReleaseController(IController controller);
  10. }
  11. }
可以看到IControllerFactory有三个方法,它们的作用如下:

1、CreateController:负责创建Controller实例,返回类型是IController类型

2、GetControllerSessionBehavior:负责设置Controller的Session行为

3、ReleaseController:可以释放Controlller相关的资源

下面我们看看一个自定义自定义的Controller Factory的完整例子:

1.1、创建一个自定义Controller Factory

 
  1. using System;
  2. using System.Web.Mvc;
  3. using System.Web.Routing;
  4. using System.Web.SessionState;
  5. using ControllerExtensibility.Controllers;
  6. namespace ControllerExtensibility.Infrastructure {
  7. public class CustomControllerFactory: IControllerFactory {
  8. public IController CreateController(RequestContext requestContext,
  9. string controllerName) {
  10. Type targetType = null;
  11. switch (controllerName) {
  12. case "Product":
  13. targetType = typeof(ProductController);
  14. break;
  15. case "Customer":
  16. targetType = typeof(CustomerController);
  17. break;
  18. default:
  19. requestContext.RouteData.Values["controller"] = "Product";
  20. targetType = typeof(ProductController);
  21. break;
  22. }
  23. return targetType == null ? null :
  24. (IController)DependencyResolver.Current.GetService(targetType);
  25. }
  26. public SessionStateBehavior GetControllerSessionBehavior(RequestContext
  27. requestContext, string controllerName) {
  28. return SessionStateBehavior.Default;
  29. }
  30. public void ReleaseController(IController controller) {
  31. IDisposable disposable = controller as IDisposable;
  32. if (disposable != null) {
  33. disposable.Dispose();
  34. }
  35. }
  36. }
  37. }
从上面我们可以看到CreateController有两个参数,第一个参数是RequestContext类型的对象,表示请求的上下文,可以用来访问或设置请求相关的信息,它有两个属性:

HttpContext:http请求上下文。

RouteData:MVC路由相关信息。

第二个是要创建的controller名。

在CreateController方法的最后使用了MVC内置的依赖注入容器解析类来创建一个类的实例:

 
  1. return targetType == null ? null :
  2. (IController)DependencyResolver.Current.GetService(targetType);

1.2、注册自定义Controller Factory类到MVC5框架,使其生效

自定义Controller Factory类在项目中要生效,必须要注册到MVC5框架中。注册自定义Controller Factory类会用到类ControllerBuilder类,如下:

 
  1. using System;
  2. using System.Collections.Generic;
  3. using System.linq;
  4. using System.Web;
  5. using System.Web.Http;
  6. using System.Web.Mvc;
  7. using System.Web.Routing;
  8. using ControllerExtensibility.Infrastructure;
  9. namespace ControllerExtensibility {
  10. public class MvcApplication : System.Web.HttpApplication {
  11. protected void Application_Start() {
  12. AreaRegistration.RegisterAllAreas();
  13. WebApiConfig.Register(GlobalConfiguration.Configuration);
  14. FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters)
  15. RouteConfig.RegisterRoutes(RouteTable.Routes);
  16. ControllerBuilder.Current.SetControllerFactory(new
  17. CustomControllerFactory());
  18. }
  19. }
  20. }
一旦这个CustomControllerFactory被注册成功了,它就负责请求创建相应的Controller实例并做出响应。

二、使用MVC5自带的Controller Factory即DefaultControllerFactory

注意:上面实现了一个自定义了的ControllerFactory,你应该明白了ControllerFactory的作用了,但是不建议你自己实现ControllerFactory,因为你负责处理一些潜在的问题,比如:有歧义的Controller名字--不同命名空间相同名称的Controller类,构造函数异常等等。其实最快速有效的方式是使用MVC框架的自带的Controller Factory,DefaultControllerFactory,因为这些问题都为我们解决了。但是要使用DefaultControllerFactory,Controller类必须要满足一下几个条件:

1、类必须是public的

2、类不能够是abstract抽象的

3、类不能够带有泛型参数

4、类名必须要以Controller结尾

5、类必须实现接口IController

DefaultControllerFactory自身会维护保持这一个满足以上条件的类列表,这样不用每次请求都去项目中搜索这样类。

2.1、设置Controller的命名空间的优先级

我们可以设置指定命名空间的Controller就先去匹配,如下:

 
  1. public class MvcApplication : System.Web.HttpApplication {
  2. protected void Application_Start() {
  3. AreaRegistration.RegisterAllAreas();
  4. WebApiConfig.Register(GlobalConfiguration.Configuration);
  5. FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
  6. RouteConfig.RegisterRoutes(RouteTable.Routes);
  7. ControllerBuilder.Current.DefaultNamespaces.Add("MyControllerNamespace");
  8. ControllerBuilder.Current.DefaultNamespaces.Add("MyProject.*");
  9. }
  10. }
上面我们用静态方法ControllerBuilder.Current.DefaultNamespaces.Add,设置了两个命名空间。


注意:这里两个Add是不分先后顺序的,并不表示写在前面就先去对应命名空间搜索。

2.2、自定义DefaultControllerFactory创建Controlller的实例

自定义DefaultControllerFactory创建Controlller的实例的方式有很多种,有时为了把我们的项目耦合性降低,我们一般会引入DI(依赖注入)。

1、使用MVC自带的Dependency Resolver

当有Dependency Resolver可用时,DefaultControllerFactory会使用它来创建Controller实例。

定义一个Dependency Resolver

 
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Web.Mvc;
  4. using Ninject;
  5. using Ninject.Parameters;
  6. using Ninject.Syntax;
  7. using System.Configuration;
  8. using EssentialTools.Models;
  9. namespace EssentialTools.Infrastructure {
  10. public class NinjectDependencyResolver : IDependencyResolver {
  11. private IKernel kernel;
  12. public NinjectDependencyResolver() {
  13. kernel = new StandardKernel();
  14. AddBindings();
  15. }
  16. public object GetService(Type serviceType) {
  17. return kernel.TryGet(serviceType);
  18. }
  19. public IEnumerable<object> GetServices(Type serviceType) {
  20. return kernel.GetAll(serviceType);
  21. }
  22. private void AddBindings() {
  23. kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
  24. }
  25. }
  26. }

上面使用依赖注入DI(Ioc框架)--Ninject,最后在Gloabl中注册上面的NinjectDependencyResolver

 
  1. using EssentialTools.Infrastructure;
  2. using System.Web.Http;
  3. using System.Web.Mvc;
  4. using System.Web.Routing;
  5. namespace EssentialTools {
  6. public class MvcApplication : System.Web.HttpApplication {
  7. protected void Application_Start() {
  8. AreaRegistration.RegisterAllAreas();
  9. DependencyResolver.SetResolver(new NinjectDependencyResolver());
  10. WebApiConfig.Register(GlobalConfiguration.Configuration);
  11. FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
  12. RouteConfig.RegisterRoutes(RouteTable.Routes);
  13. }
  14. }
  15. }

2、使用一个Controller Activator 

除了上面使用DependencyResolver来控制DefaultControllerFactory创建Controller,还可以定义一个Controller Activator,然后把这个类的实例通过DefaultControllerFactory的构造函数传进去。

我们先来看一看定义一个Controller Activator要用到的接口IControllerActivator:

 
  1. namespace System.Web.Mvc {
  2. using System.Web.Routing;
  3. public interface IControllerActivator {
  4. IController Create(RequestContext requestContext, Type controllerType);
  5. }
  6. }
下面是一个完整的Controller Activator的定义:
 
  1. using ControllerExtensibility.Controllers;
  2. using System;
  3. using System.Web.Mvc;
  4. using System.Web.Routing;
  5. namespace ControllerExtensibility.Infrastructure {
  6. public class CustomControllerActivator : IControllerActivator {
  7. public IController Create(RequestContext requestContext,
  8. Type controllerType) {
  9. if (controllerType == typeof(ProductController)) {
  10. controllerType = typeof(CustomerController);
  11. }
  12. return (IController)DependencyResolver.Current.GetService(controllerType);
  13. }
  14. }
  15. }
最后在Global.asax 中注册使用这个 Controller Actionvator:
 
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using System.Web;
  4. using System.Web.Http;
  5. using System.Web.Mvc;
  6. using System.Web.Routing;
  7. using ControllerExtensibility.Infrastructure;
  8. namespace ControllerExtensibility {
  9. public class MvcApplication : System.Web.HttpApplication {
  10. protected void Application_Start() {
  11. AreaRegistration.RegisterAllAreas();
  12. WebApiConfig.Register(GlobalConfiguration.Configuration);
  13. FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
  14. RouteConfig.RegisterRoutes(RouteTable.Routes);
  15. ControllerBuilder.Current.SetControllerFactory(new
  16. DefaultControllerFactory(new CustomControllerActivator()));
  17. }
  18. }
  19. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值