ASP.NET MVC 4 (二)控制器
MVC中控制器負責處理請求,由它操作數據模型,最后返回視圖給用戶。
IController接口
所有的控制器類以Controller結尾,必須實現System.Web.Mvc.IController接口,一個最簡單的控制器類可以是:
public class BasicController : IController {
public void Execute(RequestContext requestContext) {
string controller = (string)requestContext.RouteData.Values["controller"];
string action = (string)requestContext.RouteData.Values["action"];
if (action.ToLower() == "redirect") {
requestContext.HttpContext.Response.Redirect("/Derived/Index");
} else {
requestContext.HttpContext.Response.Write(
string.Format("Controller: {0}, Action: {1}",
controller, action));
}
}
}
BasicController類實現了IController的唯一方法Execute(),在上面的例子中直接返回數據到請求響應,我們可以根據自己的需求來靈活的處理客戶請求。
Controller類
更多的時候我們直接繼承MVC已經定義的控制類System.Web.Mvc.Controller:
public class DerivedController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Hello from the DerivedController Index method";
return View("MyView");
}
}
Controller類封裝的IController.Execute()方法會調用我們定義的Action方法,比如這里的Index()。Controller同時為我們提供了眾多的屬性來方便獲取相關數據:
- Request:比如Request.QueryString、Request.Url、Request.Form、Request.HttpMethod等。
- Response:可以直接向Response返回數據到用戶。
- RouteData:和路徑映射相關的數據,比如RouteData.Route、RouteData.Values。
- HttpContext:比如HttpContext.HttpSessionStateBAse、HttpContext.Items。
- User:當前已會話已認證的用戶信息。
- TempData:存儲當前用戶的一些臨時信息,可以傳遞給View。
一些獲取Controller數據的例子:
string userName = User.Identity.Name;
string serverName = Server.MachineName;
string clientIP = Request.UserHostAddress;
DateTime dateStamp = HttpContext.Timestamp;
AuditRequest(userName, serverName, clientIP, dateStamp, "Renaming product");
// Retrieve posted data from Request.Form
string oldProductName = Request.Form["OldName"];
string newProductName = Request.Form["NewName"];
bool result = AttemptProductRename(oldProductName, newProductName);
ViewData["RenameResult"] = result;
return View("ProductRenamed");
Action方法參數
控制器Action方法可以帶一系列的參數,比如:
...
public ActionResult ShowWeatherForecast(string city, DateTime forDate) {
// ... implement weather forecast here ...
return View();
}
...
這些參數是由MVC的Value providers和model binders所提供的,MVC自動從請求數據等中自動按名稱為我們解析參數值并做類型轉換,比如上面例子中的city和forDate可能來自于:
string city = (string)RouteData.Values["city"]; DateTime forDate = DateTime.Parse(Request.Form["forDate"]);
響應輸出
我們可以從Icontroller的Excecute()方法中直接輸出響應,也可以在Controller中使用Response直接輸出響應:
public void ProduceOutput()
{
if (Server.MachineName == "TINY")
{
Response.Redirect("/Basic/Index");
}
else
{
Response.Write("Controller: Derived, Action: ProduceOutput");
}
}
這里的Action方法ProduceOutput沒有返回值,更多的時候,我們返回一個ActionResult對象,比如View("MyView")返回一個ViewResult,ViewResult繼承自ActionResult。甚至我們可以創建自定義的ActionResult類來使用:
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);
}
}
在控制器Action方法中返回自定義的ActionResult對象:
public ActionResultProduceOutput() {
if (Server.MachineName == "TINY") {
return new CustomRedirectResult { Url = "/Basic/Index" };
} else {
Response.Write("Controller: Derived, Action: ProduceOutput");
return null;
}
}
這里創建了一個實現重定向的ActionResult對象,實際上MVC已經為我們提供了RedirectResult來實現這個功能:
...
public ActionResult ProduceOutput() {
return new RedirectResult("/Basic/Index");
}
...
或者更方便的調用Controller的Redirect()方法:
...
public ActionResult ProduceOutput() {
return Redirect("/Basic/Index");
}
...
除了RedirectResult,MVC還提供這些ActionResult:
- ViewResult:渲染一個視圖,等同于控制器中調用View()
- PartialViewResult:渲染部分視圖,等同于控制器中調用PartialView()
- RedirectToRouteResult:根據指定的路由信息發出一個HTTP 301或者302重定向命令,等同于控制器調用RedirectToAction 、RedirectToActionPermanent 、RedirectToRoute 、RedirectToRoutePermanent。
- HttpUnauthorizedResult:設置HTTP狀態碼401表示未授權。
- HttpNotFoundResult:返回HTTP 404-NOT FOUD錯誤,等同于控制器調用HttpNotFound()。
- HttpStatusCodeResult:返回自定義的HTTP狀態碼
- EmptyResult:不返回任何信息。
返回視圖
用得最多的就是在控制器Action方法中返回一個視圖,由它渲染HTML返回給用戶。我們可以不帶任何參數調用View(),MVC會查找和Action方法同名(不帶Controller)的View,也可以直接在參數中指定視圖的名稱:
public ViewResult Index() {
return View("Homepage");
}
MVC在應用目錄下搜索視圖,如果啟用了區域Area,搜索路徑為:
? /Areas/<AreaName>/Views/<ControllerName>/<ViewName>.aspx ? /Areas/<AreaName>/Views/<ControllerName>/<ViewName>.ascx ? /Areas/<AreaName>/Views/Shared/<ViewName>.aspx ? /Areas/<AreaName>/Views/Shared/<ViewName>.ascx ? /Areas/<AreaName>/Views/<ControllerName>/<ViewName>.cshtml ? /Areas/<AreaName>/Views/<ControllerName>/<ViewName>.vbhtml ? /Areas/<AreaName>/Views/Shared/<ViewName>.cshtml ? /Areas/<AreaName>/Views/Shared/<ViewName>.vbhtml
如果沒有使用Area,搜索路徑為:
? /Views/<ControllerName>/<ViewName>.aspx ? /Views/<ControllerName>/<ViewName>.ascx ? /Views/Shared/<ViewName>.aspx ? /Views/Shared/<ViewName>.ascx ? /Views/<ControllerName>/<ViewName>.cshtml ? /Views/<ControllerName>/<ViewName>.vbhtml ? /Views/Shared/<ViewName>.cshtml ? /Views/Shared/<ViewName>.vbhtml
MVC如果按照上述順序搜索視圖,如果找到一個文件就停止搜索,如果沒有可用的視圖文件會返回資源未找到錯誤。注意MVC會搜索ASPX視圖引擎的老式文件.aspx和.ascx。
View方法還有其他一些重載調用方式:
return View("Index", "_AlternateLayoutPage"); //指定要使用的布局模板
return View("~/Views/Other/Index.cshtml"); //直接指定要使用的視圖模板,必須以/或者~/開頭。
從控制器向視圖傳遞數據
我們可以在調用View()直接指定要傳遞給視圖的數據:
...
public ViewResult Index() {
DateTime date = DateTime.Now;
return View(date);
}
...
在視圖中使用傳入的數據:
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
The day is: @(((DateTime)Model).DayOfWeek)
對于強類型的視圖,使用起來更方便:
@model DateTime
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
The day is: @Model.DayOfWeek
也可以使用ViewBag來傳遞,它是一個動態的鍵值對集合:
public ViewResult Index() {
ViewBag.Message = "Hello";
ViewBag.Date = DateTime.Now;
return View();
}
在視圖中使用:
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
The day is: @ViewBag.Date.DayOfWeek
<p />
The message is: @ViewBag.Message
Viewbag比視圖模型好在可以傳遞多個值,但是VS不會給出IntelliSense提示,只會在渲染視圖時給出錯誤信息。
重定向
在上面我們已經看到可以使用Redirect重定向請求:
public RedirectResult Redirect() {
return Redirect("/Example/Index");
}
也可以使用RedirectPermanent永久重定向:
return RedirectPermanent("/Example/Index");
和Redirect臨時重定向發出302 HTTP代碼不同,RedirectPermanent發回301 HTTP代碼,前者指示瀏覽器重新GET新的URL,而后者指示瀏覽器緩存重定向信息,以后針對老URL的請求自動轉向新URL。
除了重定向到URL,我們可以重定向到路徑映射方法:
public RedirectToRouteResult Redirect() {
return RedirectToRoute(new { controller = "Example", action = "Index", ID = "MyID" });
}
或者一個Action方法:
public RedirectToRouteResult RedirectToRoute() {
return RedirectToAction("Index");
}
可以指定是某個控制器的某個Action方法:
public RedirectToRouteResult Redirect() {
return RedirectToAction("Index", "Basic");
}
如果在重定向另一個控制器的Action時我們想要傳遞數據該怎么辦呢?我們可以使用TempData:
public RedirectToRouteResult RedirectToRoute() {
TempData["Message"] = "Hello";
TempData["Date"] = DateTime.Now;
return RedirectToAction("Index");
}
在新的視圖中讀取TempData:
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
The day is: @(((DateTime)TempData["Date"]).DayOfWeek)
<p />
The message is: @TempData["Message"]
和ViewBag只用于控制器和同名視圖不同,TempData類似于會話Session數據,可以在不同控制器/視圖中共享,但是和Session跨請求不同的是一旦讀取了TempData的數據TempData就會被刪除。TempData.Peek讀取數據但是不刪除數據:
DateTime time = (DateTime)TempData.Peek("Date");
TempData.Keep可以標記數據不被刪除,但是如果再被讀取又會再次標記刪除,類似于引用計數器:
TempData.Keep("Date");
返回HTTP狀態碼
我們可以返回一個HTTP狀態碼比如404錯誤:
public HttpStatusCodeResult StatusCode() {
return new HttpStatusCodeResult(404, "URL cannot be serviced");
}
或者直接調用:
return HttpNotFound();
401未授權錯誤:
return new HttpUnauthorizedResult();
以上為對《Apress Pro ASP.NET MVC 4》第四版相關內容的總結,不詳之處參見原版 http://www.apress.com/9781430242369。

浙公網安備 33010602011771號