通过实现接口IController完成一个controller
对于默认的路由:
routes.MapRoute(
name: "Default",
url:"{controller}/{action}/{id}",
defaults: new { controller ="Home", action = "Index", id = UrlParameter.Optional }
);
添加controller:
public void Execute(RequestContextrequestContext)
{
var controller = (string)requestContext.RouteData.Values["controller"];
var action =(string)requestContext.RouteData.Values["action"];
requestContext.HttpContext.Response.Write(
string.Format("Controller: {0}, Action: {1}", controller,action));
}
访问controller查看结果:
vcq9o6y1q8rHzaizo7K71eLR+df2o6zS8s6qo7o8L3A+CjxwPs7Sw8fEw7W9tcTKx1JlcXVlc3RDb250ZXh0ttTP86Os0OjSqsrWtq/Ipcn6s8lodG1s0LS1vVJlc3BvbnNlwO/D5re1u9i/zbuntsujrLT6wuu9q7rcxNHOrLukoaM8L3A+CjxwPiA8L3A+CjxwPryvs8lDb250cm9sbGVywODN6rPJ0ru49mNvbnRyb2xsZXI8L3A+CjxwPtK7sOO1xKOsw7+1sc7Sw8fQwr2o0ru49mNvbnRyb2xsZXKjrLa8ysfX1LavvMyz0GNvbnRyb2xsZXLA4KOs1eK49sDg1vfSqrDvztLDx83qs8nBvbz+ysLH6aO6PC9wPgo8cD4xLiAgICAgILvhtNPCt9PJxMO1vXJlcXVlc3RDb250ZXh0ttTP86OsveLO9rP2YWN0aW9u0tS8sLLOyv2jrLKitffTwzwvcD4KPHA+Mi4gICAgICDM4bmpsrvNrLXEcmVzdWx0o6hjb21tYW5kxKPKvaOpo6y3tbvYuPi/zbuntss8L3A+CjxwPsHtzeKjrM7Sw8e7ub/J0tTKudPDZmlsdGVyo6zN6rPJsrvNrLXEY3Jvc3NjdXR0aW5ntcRjb25jZXJuo6y688Pm1cK92rvhz+rPuL3pydyhozwvcD4KPHA+08nT2tL9yOvBy2FjdGlvbrrNcmVzdWx0tcS4xcTuo6zKubXDztLDx7XEtPrC67j8yN3S17Wl1Kqy4srUo6zG8MLrscjO0sPH19S8urzMs9BJQ29udHJvbGxlcr3Tv9qjrNaxvdOy2df3UmVxdWVzdENvbnRleHS21M/zyN3S17rctuChozwvcD4KPHA+IDwvcD4KPGgyPmNvbnRyb2xsZXLKvsD9o7o8L2gyPgo8cD4gPC9wPgo8cD48cHJlIGNsYXNzPQ=="brush:java;">public class DerivedController :Controller {
public ActionResult Index() {
ViewBag.Message = "Hellofrom the DerivedController Index method";
return View("MyView");
}
}
View代码:
@{
ViewBag.Title ="MyView";
}
MyView
Message: @ViewBag.Message
代码很简单,就是用Viewbag传值到View显示出来,Controller返回了最常用的result,ViewResult。
从controller获取客户端传值的方式
1. 从context object 直接提取
2. 通过参数传进来(由基类controller完成解析)
3. 通过model binding
context object常用的对象
Request.QueryString
从Get 请求的url中取
Request.Form
从Post请求的表单取
Request.Cookies
把值放在请求的cookie里带过来
RouteData.Route
从路由表里取注册的路由名
RouteData.Values
从路由表获取路由配置的匿名对象
HttpContext.Cache
应用程序缓存
HttpContext.Items
存储一些值,只在同一请求中使用(可以在httppipeline过程的不同module,handler,以及页面传递值)
HttpContext.Session
当前用户的session
TempData
存一些临时值,取出后会被自动删除
另外,不建议直接从RouteData.Values直接取传来的参数值:
public ActionResult ShowWeatherForecast() {
string city =(string)RouteData.Values["city"];
DateTime forDate =DateTime.Parse(Request.Form["forDate"]);
return View(forDate);
}
建议改写为传参:
public ActionResult ShowWeatherForecast(string city, DateTime forDate) {
return View(forDate);
}
关于传参,注意:
1. 对于引用类型,如果RouteData没有拿到参数,那么就给null了,如果要避免接收null,可以使用默认参数
2. 对于值类型,如果没有拿到参数,就会抛出异常,因此,建议值类型总提供默认参数,或者使用Nullable类型
例如:
public ActionResult Search(stringquery= "all", int page = 1) {
// ...process request...
return View();
}
使用Execute Result
Controller的职责:
1. 操作domain model
2. 返回一个合适的result
操作完domainmodel之后,就要给客户端返回result了,不推荐手动去实现IController接口进行Redirect或者直接Response.Write数据给客户端。前面说过了:
1. 直接输出html,或者直接跳转url,降低了可读性和可维护性
2. 很难单元测试
3. 交接很难上手
使用ActionResult
MVC Framework 的controller已经给我们了足够的result类型来返回给客户端完成交互。为了了解ActionResult,先customize一个:
public class CustomRedirectResult: ActionResult {
public string Url { get; set; }
public override void ExecuteResult(ControllerContextcontext) {
string fullUrl =UrlHelper.GenerateContentUrl(Url, context.HttpContext);
context.HttpContext.Response.Redirect(fullUrl);
}
}
要customize一个result,需要继承ActionResult,主要实现ExecuteResult方法,MVCFramework给我们了一个controllerContext对象,里面有足够我们需要的信息,以上创建的actionResult功能:指定一个url,拿到controllerContext对象生成一个fullurl,完成跳转。
使用这个result:
public ActionResult ProduceOutput() {
if (Server.MachineName == "IORI"){
return new CustomRedirectResult {Url = "/Basic/Index" };
} else {
Response.Write("Controller:Derived, Action: ProduceOutput");
return null;
}
}
常用的result:
ViewResult
返回一个view,可以指定不同的controller
ParcialViewResult
返回部分view
RedirectToActionResult
转到另一个action
RedirectResult
返回301或者302(permanent)
JsonResult
返回js最喜欢的json,常用,尤其当前段打算采用纯js template,或者single page application
FileResult
文件result
ContentResult
字符串
HttpUnauthorizedResult
401,通常,会自动跳转到登陆页面
HttpNotFoundResult
404
返回viewResult时,查找顺序:
1. /Views//.aspx
2. /Views//.ascx
3. /Views/Shared/.aspx
4. /Views/Shared/.ascx
5. /Views//.cshtml
6. /Views//.vbhtml
7. /Views/Shared/.cshtml
8. /Views/Shared/.vbhtml
可以看到,mvcframework会先从熟悉的aspx和ascx找起
直接传递路径,返回指定view
public ViewResult Index() {
return View("~/Views/Other/Index.cshtml");
}
如果出现类似以上的代码,请思考两个问题:
想要跳转到另一个action?可以考虑使用RedirectToAction
View是否放错了位置?
Action传值到View
Model Object
public ViewResult Index() {
DateTime date = DateTime.Now;
return View(date);
}
View中:
@model DateTime
@{
ViewBag.Title ="Index";
}
Index
The day is: @Model.DayOfWeek
ViewBag
public ViewResult Index() {
ViewBag.Message ="Hello";
ViewBag.Date = DateTime.Now;
return View();
}
View中:
@{
ViewBag.Title ="Index";
}
Index
The day is:@ViewBag.Date.DayOfWeek
The message is: @ViewBag.Message
ViewBag优点:
可以不需要定义类型直接传递,并且可以传递任意个对象
缺点:
错误总是运行时,由于是DynamicObject(实际是DynamicViewDataDictionary继承自DynamicObject,因此是像其他functionlanguage语言一样可以动态扩展的)
跳重定向到指定url
HttpStatusCode : 302(临时重定向)
public RedirectResult Redirect(){
return Redirect("/Example/Index");
}
HttpStatusCode:301 (永久重定向,使用小心,不常用)
public RedirectResult Redirect(){
return RedirectPermanent("/Example/Index");
}
跳转回route
public RedirectToRouteResult Redirect() {
return RedirectToRoute(new {
controller = "Example",
action = "Index",
ID = "MyID"
});
}
大多数情况,遇到处理不掉的请求,我们起码是可以确定跳转到哪个controller和action的:
public RedirectToRouteResult RedirectToRoute() {
return RedirectToAction("Index");
}
可以指定controller:
public RedirectToRouteResult Redirect() {
return RedirectToAction("Index", "Basic");
}
Redirection过程中传值
在MVCframework中,理想选择应该是使用TempData:
赋值:
public RedirectToRouteResult RedirectToRoute() {
TempData["Message"] ="Hello";
TempData["Date"] =DateTime.Now;
return RedirectToAction("Index");
}
取值:
public ViewResult Index() {
ViewBag.Message =TempData["Message"];
ViewBag.Date =TempData["Date"];
return View();
}
这个对象的好处是,取完就被标记为removable了,请求完毕会自动清掉。如果想取多次,那么可以使用peek方法(但是还是建议最后一次取了清掉(用索引取)):
TempData.Peek("Date");
另外,笔者还推荐HttpRequest.Items,也是在httppipeline内传值的一个不错的选择。
返回httpstatus code
404 (url 找不到):
public HttpStatusCodeResult StatusCode() {
return new HttpStatusCodeResult(404, "URL cannot be serviced");
}
401(访问权限受限):
public HttpStatusCodeResult StatusCode() {
return new HttpUnauthorizedResult();
}