【ASP.NET MVC 学习笔记】- 11 Controller和Action(2)
本文参考:http://www.cnblogs.com/willick/p/3331513.html
1、MVC一个请求的发出至action返回结果的流程图如下:
重点是Controller Factory 和 Action Invoker。Controller Factory的作用是创建为请求提供服务的Controller实例;Action Invoker的作用是寻找并调用Action方法。
2、自定义Controller Factory需要实现IControllerFactory接口(实际开发中不建议这样做)。示例如下:
public class CustomControllerFactory : IControllerFactory
{
//当MVC框架需要一个 Controller 来处理请求时调用
public IController CreateController(RequestContext requestContext, string controllerName)
{
Type targetType = null;
switch (controllerName)
{
case "Product":
targetType = typeof(ProductController);
break;
case "Customer":
targetType = typeof(CustomerController);
break;
default:
//在自定义的Cotroller Factory中,我们可以任意改变系统默认的行为。下列语句将路由的controller值改为Product,使得执行的cotroller并不是用户所请求的controller
requestContext.RouteData.Values["controller"] = "Product";
targetType = typeof(ProductController);
break;
}
return targetType == null ? null : (IController)DependencyResolver.Current.GetService(targetType);
} public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
{
return SessionStateBehavior.Default;
} public void ReleaseController(IController controller)
{
IDisposable disposable = controller as IDisposable;
if (disposable != null) {
disposable.Dispose();
}
}
}
获取Controller实例:
//静态的 DependencyResolver.Current 属性返回一个 IDependencyResolver 接口的实现,这个实现中定义了 GetService 方法,它根据 System.Type 对象(targetType)参数自动为我们创建 targetType 实例
return targetType == null ? null : (IController)DependencyResolver.Current.GetService(targetType); //要使用自定义的Controller Factory还需要在 Global.asax.cs 文件的 Application_Start 方法中对自定义的 CustomControllerFactory 类进注册
protected void Application_Start()
{
ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
}
3、使用内置的DefaultControllerFactory,当它从路由系统接收到一个请求,从路由实例中解析出controller名称,然后根据名称寻找controller类,这个controller类必须满足一下条件:
- 必须是public。
- 必须是具体的类(非抽象类)。
- 没有泛型参数。
- 类的名称必须以Controller结尾。
- 类必须(间接或直接)实现IController接口。
DefaultControllerFactory类维护了一个满足以上标准的类的列表,这样当每次接收到一个请求时不需要再去搜索一遍。当它找到了合适的 controller 类,则使用Controller Activator(一会介绍)来创建Controller 类的实例。其内部是通过 DependencyResolver 类进行依赖解析创建 controller 实例的。
DefaultControllerFactory可被重写方法有:
- GetControllerType,返回Type类型,为请求匹配对应的 controller 类,用上面定义的标准来筛选 controller 类也是在这里执行的。
- GetControllerInstance,返回是IController类型,作用是根据指定 controller 的类型创建类型的实例。
- CreateController 方法,返回是 IController 类型,它是 IControllerFactory 接口的 CreateController 方法的实现。默认情况下,它调用 GetControllerType 方法来决定哪个类需要被实例化,然后把controller 类型传递给GetControllerInstance。
重写DefaultControllerFactory的 GetControllerInstance 方法,可以实现对创建 controller 实例的过程进行控制,最常见的是进行依赖注入。
4、当 DefaultControllerFactory 类接收到一个 controller 实例的请求时,在 DefaultControllerFactory 类内部通过 GetControllerType 方法来获得 controller 的类型,然后把这个类型传递给 GetControllerInstance 方法以获得 controller 的实例。
所以在 GetControllerInstance 方法中就需要有某个东西来创建 controller 实例,这个创建的过程就是 controller 被激活的过程。
默认情况下 MVC 使用 DefaultControllerActivator 类来做 controller 的激活工作,它实现了 IControllerActivator 接口。
自定义ControllerActivator示例:
//如果请求的是 ProductController 则我们给它创建 CustomerController 的实例
public class CustomControllerActivator : IControllerActivator
{
public IController Create(RequestContext requestContext, Type controllerType)
{
if (controllerType == typeof(ProductController)) {
controllerType = typeof(CustomerController);
}
return (IController)DependencyResolver.Current.GetService(controllerType);
}
} //注册
protected void Application_Start()
{
ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new CustomControllerActivator()));
}
5、当 Controller Factory 创建好了一个类的实例后,MVC框架则需要一种方式来调用这个实例的 action 方法。如果创建的 controller 是继承 Controller 抽象类的,那么则是由 Action Invoker 来完成调用 action 方法的任务,MVC 默认使用的是 ControllerActionInvoker 类。如果是直接继承 IController 接口的 controller,那么就需要手动来调用 action 方法。自定义Action Invoker(一般不建议这么做)示例:
public class CustomActionInvoker : IActionInvoker
{
//如果请求的是Index Action,这个 Invoker 通过 Response 直接输出一个消息,如果不是请Index Action,则会引发一个404-未找到错误
public bool InvokeAction(ControllerContext controllerContext, string actionName)
{
if (actionName == "Index")
{
controllerContext.HttpContext.Response.Write("This is output from the Index action");
return true;
}
else
{
return false;
}
}
}
创建一个ActionInvokerController,并在它的构造函数中指定了 Action Invoker 为我们自定义的 Action Invoker:
public class ActionInvokerController : Controller
{
public ActionInvokerController()
{
this.ActionInvoker = new CustomActionInvoker();
}
}
6、通过自定义 Action Invoker,我们知道了MVC调用 Action 方法的机制。我们创建一个继承自 Controller 抽象类的 controller,如果不指定Controller.ActionInvoker,那么MVC会使用内置默认的Action Invoker,它是 ControllerActionInvoker 类。它的工作是把请求匹配到对应的 Action 方法并调用之,简单说就是寻找和调用 Action 方法。Action方法必须满足:
- 必须是公共的(public)。
- 不能是静态的(static)。
- 不能是System.Web.Mvc.Controller中存在的方法,或其他基类中的方法。如方法不能是 ToString 和 GetHashCode 等。
- 不能是一个特殊的名称。所谓特殊的名称是方法名称不能和构造函数、属性或者事件等的名称相同。
- 不能带有泛型。
7、默认情况下,内置的Action Invoker (ControllerActionInvoker)寻找的是和请求的 action 名称相同的 action 方法。比如路由系统提供的 action 值是 Index,那么 ControllerActionInvoker 将寻找一个名为 Index 的方法,如果找到了,它就用这个方法来处理请求。ControllerActionInvoker 允许我们对此行为进行调整,即可以通过使用 ActionName 特性对 action 使用别名,如下对 CustomerController 的 List action 方法使用 ActionName 特性:
public class CustomerController : Controller
{
//当请求 Enumerate Action 时,将会使用 List 方法来处理请求。请求/Customer/List 会报错
[ActionName("Enumerate")]
public ViewResult List()
{
return View("Result", new Result {
ControllerName = "Customer",
ActionName = "List"
});
}
}
使用 Action 方法别名有两个好处:一是可以使用非法的C#方法名来作为请求的 action 名,如 [ActionName("User-Registration")]。二是,如果你有两个功能不同的方法,有相同的参数相同的名称,但针对不同的HTTP请求(一个使用 [HttpGet],另一个使用 [HttpPost]),你可以给这两个方法不同的方法名,然后使用 [ActionName] 来指定相同的 action 请求名称。
8、我们经常会在 controller 中对多个 action 方法使用同一个方法名。在这种情况下,我们就需要告诉 MVC 怎样在相同的方法名中选择正确的 action 方法来处理请求。这个机制称为 Action 方法选择,它在基于识别方法名称的基础上,允许通过请求的类型来选择 action 方法。MVC 框架可使用C#特性来做到这一点,所以这种作用的特性可以称为 Action 方法选择器。
MVC提供了几种内置的特性来支持 Action 方法选择,它包括HttpGet、HttpPost、HttpPut 和 NonAction 等。
9、除了使用内置的Action方法选择器外,我们也可以自定义。所有的 action 选择器都继承自 ActionMethodSelectorAttribute 类,这个类的定义如下:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public abstract class ActionMethodSelectorAttribute : Attribute
{
public abstract bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo);
}
以下示例演示自定义Action选择器,实现同一个URL,本地和远程请求不同的Action方法。
//定义Attribute
public class LocalAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
return controllerContext.HttpContext.Request.IsLocal;
}
} //使用
public class CustomerController : Controller
{ public ViewResult Index()
{
return View("Result", new Result
{
ControllerName = "Customer",
ActionName = "Index"
});
}
//不加Local,如果请求 /Customer/Index,这两个 action 方法都会被匹配到而引发歧义问题,程序将会报错。
[Local]
[ActionName("Index")]
public ViewResult LocalIndex()
{
return View("Result", new Result {
ControllerName = "Customer",
ActionName = "LocalIndex"
});
}
...
}
10、Excute 方法是(自定义或默认的)ActionInvoker 的入口函数。ActionInvoker 必须实现 IActionInvoker 接口来查找和调用 Action 方法。本文没有介绍 MvcHandler 的知识。MvcHandler 是处理Controller的开始,但在MvcHandler 之前还有一个MvcRouteHandler,当请求经过路由解析后,MvcRouteHandler 实例会生成一个 MvcHandler 实例,并把请求交给它。MvcHandler 会从Controller 工厂中获取一个 Controller 实例,然后由 Controller 来具体地处理请求。
【ASP.NET MVC 学习笔记】- 11 Controller和Action(2)的更多相关文章
- ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET MVC 学习笔记-6.异步控制器 ASP.NET MVC 学习笔记-5.Controller与View的数据传递 ASP.NET MVC 学习笔记-4.ASP.NET MVC中Ajax的应用 ASP.NET MVC 学习笔记-3.面向对象设计原则
ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET程序中的web.config文件中,在appSettings这个配置节中能够保存一些配置,比如, 1 <appSettin ...
- ASP.NET MVC 学习笔记-5.Controller与View的数据传递
ViewData属性 ViewData属性是System.Web.Mvc.ControllerBase中的一个属性,它相当于一个数据字典.Controller中向该字典写入数据,ViewData[“K ...
- 【ASP.NET MVC 学习笔记】- 13 Child Action
本文参考:http://www.cnblogs.com/willick/p/3410855.html 1.Child action 和 Patial view 类似,也是在应用程序的不同地方可以重复利 ...
- ASP.NET MVC 学习笔记-2.Razor语法 ASP.NET MVC 学习笔记-1.ASP.NET MVC 基础 反射的具体应用 策略模式的具体应用 责任链模式的具体应用 ServiceStack.Redis订阅发布服务的调用 C#读取XML文件的基类实现
ASP.NET MVC 学习笔记-2.Razor语法 1. 表达式 表达式必须跟在“@”符号之后, 2. 代码块 代码块必须位于“@{}”中,并且每行代码必须以“: ...
- ASP.NET MVC学习笔记-----Filter2
ASP.NET MVC学习笔记-----Filter(2) 接上篇ASP.NET MVC学习笔记-----Filter(1) Action Filter Action Filter可以基于任何目的使用 ...
- ASP.NET MVC学习笔记-----Filter
ASP.NET MVC学习笔记-----Filter(1) Filter类型 接口 MVC的默认实现 Description Authorization IAuthorizationFilter Au ...
- ASP.NET MVC学习笔记-----Filter(2)
接上篇ASP.NET MVC学习笔记-----Filter(1) Action Filter Action Filter可以基于任何目的使用,它需要实现IActionFilter接口: public ...
- Spring MVC 学习笔记11 —— 后端返回json格式数据
Spring MVC 学习笔记11 -- 后端返回json格式数据 我们常常听说json数据,首先,什么是json数据,总结起来,有以下几点: 1. JSON的全称是"JavaScript ...
- 【转】ASP.NET MVC学习笔记-Controller的ActionResult
1. 返回ViewResult public ActionResult Index() { ViewData["Message"] = "Welcome ...
随机推荐
- 201521123013 《Java程序设计》第12周学习总结
1. 本章学习总结 2. 书面作业 将Student对象(属性:int id, String name,int age,double grade)写入文件student.data.从文件读出显示. Q ...
- audio标签
实例 一段简单的 HTML 5 音频: <audio src="someaudio.wav"> 您的浏览器不支持 audio 标签. </audio> 亲自 ...
- python之---进程
一.进程 1.什么是进程 (1)正在进行的一个过程或者说一个任务,而负责执行的就是CPU 2.进程与程序的区别 (1)程序仅仅是一堆代码而已,而进程指的是程序的运行过程 同一个程序执行两次,也是两个进 ...
- WebUtils复用代码【request2Bean、UUID】
request封装到Bean对象 public static <T> T request2Bean(HttpServletRequest httpServletRequest, Class ...
- JavaSE(十二)之IO流的字节流(一)
前面我们学习的了多线程,今天开始要学习IO流了,java中IO流的知识非常重要.但是其实并不难,因为他们都有固定的套路. 一.流的概念 流是个抽象的概念,是对输入输出设备的抽象,Java程序中 ...
- 【SQL】- 基础知识梳理(四) - 存储过程
存储过程的概念 存储过程Procedure是一组为了完成特定功能的SQL语句集合,经编译后存储在数据库中,用户通过指定存储过程的名称并给出参数来执行 存储过程的好处 A. 存储过程允许标准组件式编程 ...
- 使用phpmailer插件发邮件失败提示:SMTP -> ERROR: Failed to connect to server: Connection timed out (110) smtp connect() failed;
一个邮件发送问题,整整弄了我一周时间,起因是这样的,之前弄的一个网站,需要在邮箱里面认证之后才可以注册成功.网站上线了差不多一年之后,客户突然跟我说,网站不能注册了,然后我就查看了一下代码. 发现报这 ...
- SQL server2005学习笔记(一)数据库的基本知识、基本操作(分离、脱机、收缩、备份、还原、附加)和基本语法
在软件测试中,数据库是必备知识,假期闲里偷忙,整理了一点学习笔记,共同探讨. 阅读目录 基本知识 数据库发展史 数据库名词 SQL组成 基本操作 登录数据库操作 数据库远程连接操作 数据库分离操作 数 ...
- 使用SQLite做本地数据缓存的思考
前言 在一个分布式缓存遍地都是的环境下,还讲本地缓存,感觉有点out了啊!可能大家看到标题,就没有想继续看下去的欲望了吧.但是,本地缓存的重要性也是有的! 本地缓存相比分布式缓存确实是比较out和比较 ...
- 未能写入输出文件“c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root
打开服务器系统c盘,打开window, 右键temp 属性 安全 编辑 添加IIS_IUSRS 用户控制权限添加修改和写入权限即可.这是Windows Server 2008 R2 标准版 SP1 6 ...