Controller做为持久层和展示层的桥梁, 封装了应用程序的逻辑,是MVC中的核心组件之一。html
本篇文章咱们就来谈谈 Controller, 主要讨论两个方面:web
咱们本身要实现一个控制器有两种方法:
一种是继承IController接口,一种是继承Controller或ControllerBase.
Controller继承了ControllerBase, 另外Controller和ControllerBase自己也继承了IController,总之须要实现IController接口.
首先咱们到XEngine中随便打开一个Controller, 例如AccountController,
能够看到新建Controller时,脚手架帮咱们继承了Controller类
浏览器
咱们逐级查看,以下几张图,右键 转到Controller定义--> 查看ControllerBase定义 --> 查看IController定义,能够看到Controller须要实现IController中Execute方法。
mvc
接下来,咱们就新建一个类MyCustomController,继承IController接口,实现Execute方法。框架
namespace XEngine.Web.Controllers { public class MyCustomController:IController { public void Execute(RequestContext requestContext) { requestContext.HttpContext.Response.Write("Hello world."); } } }
运行http://localhost/XEngine/mycustom,能够看到浏览器输出了Hello world.ide
MVC框架将实现IController接口的类看成一个控制器,根据路由规则将请求发送给它。
上例中,咱们使用到了RequestContext的HttpContext属性,该属性用来获取有关HTTP请求的信息。
RequestContext另外还有一个属性RouteData,用来获取请求路由的信息,例如能够经过以下方式能够得到controller和action的名称:
requestContext.RouteData.Values["controller"].ToString();
requestContext.RouteData.Values["action"].ToString();
实现IController接口的控制器须要负责处理请求的各个方面,包括生成对客户端的响应。
实际应用中咱们像脚手架同样直接继承System.Web.Mvc.Controller就能够了,这种方式咱们就不须要本身实现Execute方法来输出内容了,能够经过MVC Framework的action results来解决这个问题。
咱们先举个例子,看看咱们原来一直使用的ActionReslut生成响应的方式,例如post
public ActionResult NativeOutput() { return Redirect("~/Account/Login"); }
Action 方法不直接使用Response对象,而是返回ActionResult类型的对象。ActionResult类描述了response的类型,好比返回一个view或跳转到另一个页面。
当MVC Framework从一个action方法接收一个ActionResult对象时,会调用那个对象的ExecuteResult方法。学习
namespace System.Web.Mvc { // 摘要: // 表示操做方法的结果。 public abstract class ActionResult { // 摘要: // 初始化 System.Web.Mvc.ActionResult 类的新实例。 protected ActionResult(); // 摘要: // 经过从 System.Web.Mvc.ActionResult 类继承的自定义类型,启用对操做方法结果的处理。 // // 参数: // context: // 用于执行结果的上下文。上下文信息包括控制器、HTTP 内容、请求上下文和路由数据。 public abstract void ExecuteResult(ControllerContext context); } }
咱们经过一个自定义的ActionResult实现来演示工做机制, 模拟实现这个简单的跳转功能, ExecuteResult实现以下:spa
namespace XEngine.Web.Utility { public class CustomRedirectResult:ActionResult { public string Url { get; set; } public override void ExecuteResult(ControllerContext context) { string fullUrl = UrlHelper.GenerateContentUrl(Url, context.HttpContext); context.HttpContext.Response.Redirect(fullUrl); } } }
在Controller中使用code
public CustomRedirectResult CustomOutput() { return new CustomRedirectResult { Url = "~/Account/Login" }; }
能够看到,实现了一样的效果。
相似于咱们实现的CustomRedirectResult,MVC框架包含一些内置的action result类型,全部这些类型都继承于ActionReslut类型。以下列表:
https://msdn.microsoft.com/en-us/library/system.web.mvc.actionresult.aspx
咱们具体使用时能够明确指明返回类型,如
public ViewResult xxx() { xxx }
或统一返回 ActionResult, 如
public ActionResult xxx() { xxx }
通常我都是笼统的返回 ActionResult,这样比较方便。(另外具体实现时,一个Action也可能根据不一样状况返回不一样种类的ActionResult,没办法明确返回类型)
上面这张表格, HttpStatusCodeResult、 HttpUnauthorizedResult、 EmptyResult这三个Action Result是没有Helper Method的.
相似于咱们自定义的CustomRedirectResult,使用时须要使用字面量来明确返回结果。下面看例子:
可使用HttpStatusCodeResult 类将一个特定的HTTP状态码发送给浏览器。下面看下HttpStatusCodeResult的例子,返回特定的HTTP结果码:
这个类没有具体的控制器辅助方法,所以必须对这个类进行实例化。
public HttpStatusCodeResult StatusCode() { return new HttpStatusCodeResult(404, "URL cannot beserviced"); }
401和404是HttpStatusCodeResult的两个特例:
可使用HttpNotFoundResult类取得上面的404效果
public HttpStatusCodeResult NotFoundStatusCode() { return HttpNotFound(); }
发送401结果,一般是把用户重定向到认证页面
public HttpStatusCodeResult UnauthorizedStatusCode() { return new HttpUnauthorizedResult(); }
能够看到,运行后跳转到认证页面
咱们讨论下一话题:MVC中经常使用的传递数据方式。(传统的Session, Cookie传递方式还能够继续用,就再也不作介绍了)
咱们使用到的数据传递主要有 view到controller, controller到view, 跨view间的数据传递三种。下面咱们分别加以说明。
Controller 常常须要访问来自输入请求的数据,如查询字符串值、表单值,以及路由系统根据输入URL解析所获得的参数。访问这些数据有两个主要途径:
一、经过context(和ASP.NET 以前版本的技术相似,如咱们熟悉的Request)
二、经过action方法的参数(包括模型绑定),(MVC框架自动检查上下文给这些参数赋值)
这两个方式都很经常使用,咱们来依次讲解。
当咱们经过继承ControllerBase类建立controller时, 咱们能够利用context对象的一组属性来获取请求的相关信息, 如Request, Response, RouteData, HttpContext和Server.
经常使用的概括以下表:
这些使用方法有些以前的文章已经介绍过,其余的在用到时再介绍,就不重复说明了。
经过参数的方法可读性更好。
以下的重写例子,咱们先用context读取表单值,再改写成参数方式读取。
先定义一个View
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>GetDataFromView</title> </head> <body> <h1>@ViewBag.Name</h1> <form method="post" > <input name="name" value="Tony"/> <input type="submit" value="提交表单" /> </form> </body> </html>
经过context读取
public ActionResult GetDataFromView() { ViewBag.Name = Request.Form["name"]; return View(); }
改为经过参数读取
public ActionResult GetDataFromView(string name) { ViewBag.Name = name; return View(); }
点击按钮后,均返回以下页面:
经过自动检查上下文对象和属性,MVC框架会给action method 参数提供值,这些对象包括Request.QueryString, Request.Form 和 RouteData.Values
模型绑定是MVC推荐的方式,我的感受可使代码更加干净。原理是经过Value Provider Model Binder 两个组件。
有一组内建的 Value Provider,它们会抓取Request.Form, Request.QueryString, Request.Files以及 RouteData.Values的数据项,而后将这些值传递给Model Binder,尝试将这些数据映射为action method参数的数据类型。
固然参数也能够是一个model, 这种方式前面文章已经使用屡次,再也不重复举例。
直接将对象做为View的参数便可(即传递一个view model object)。
public ActionResult DateOutput() { DateTime date = DateTime.Now; return View(date); }
在View中使用Model关键字来访问 @{ ViewBag.Title = "Index"; } <h2> DateOutput </h2> The day is: @(((DateTime)Model).DayOfWeek)
这种视图是无类型视图。该视图不知道关于视图模型的任何状况,而把它做为object的一个实例来看待。
能够经过建立强类型视图来明确model类型,在强类型视图中包含视图模型对象类型的详细信息。
@model DateTime @{ ViewBag.Title = "Index"; } <h2>DateOutput</h2> The day is: @Model.DayOfWeek
注意:指定模型类型是须要小写的 m, 读取时用大写的 M
以前也用过屡次,再也不赘述。
我的认为ViewBag最大的一个优势是它便于将多个对象发送给视图。
前面两种请求方式都在一轮请求应答中。
还有一种跨请求的状况,例如重定向致使浏览器递交新的HTTP请求。
若是须要将一个请求的数据传递到下一个请求,这种状况可使用TempData.
使用时直接按Session同样的语法就能够了。
TempData和Session的区别是,当读取TempData值时,值就会被标记为待删除,
当请求结束后就会被删除。
有两个小技巧:
一、利用Peek方法,能够获得TempData的值,而不把它标记为删除
DateTime time = (DateTime)TempData.Peek("Date");
二、利用Keep方法,能够保留一个将被删除的值
TempData.Keep("Date");
Keep方法不会永久保护一个值。若是这个值被再次读取,它将被再次标记为删除。
关于Controller须要了解经常使用的ActionResult类型,掌握数据的传递的几种方式。 欢迎你们多多评论,祝 学习进步:)