• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

ASP.NETMVC控制器PART2

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

以下内容摘自:

http://www.cnblogs.com/r01cn/archive/2011/12/04/2275208.html

http://www.cnblogs.com/r01cn/archive/2011/12/06/2276733.html

 

感谢作者的翻译,这里只是译文。原书名:Pro ASP.NET MVC 3 Framework

 

第十二章 控制器与动作 PART2

产生输出

控制器在完成了一个请求的处理之后,它通常需要生成一个响应。通过实现IController接口,我们直接生成的是祼机控制器(意即很原始的控制器,或者叫祼态控制器,或干脆叫做裸控制器更好些? — 译者注),我们需要负责处理一个请求的各个方面,包括生成对客户端的响应。例如,如果我们想要发送一个HTML响应,那么我们必须生成并装配HTML的数据,然后用Response.Write方法把它发送到客户端。类似地,如果我们想把用户的浏览器重定向到另一个URL,我们需要调用Response.Redirect方法,并直接传递我们感兴趣的URL。清单12-7对这两种办法都作了演示。

Listing 12-7. Generating Results in an IController Implementation

using System.Web.Mvc;
using System.Web.Routing;
namespace ControllersAndActions.Controllers {
public class BasicController : IController {
public void Execute(RequestContext requestContext) {
string controller = (string)requestContext.RouteData.Values["controller"];
string action = (string)requestContext.RouteData.Values["action"];
requestContext.HttpContext.Response.Write(
string.Format("Controller: {0}, Action: {1}", controller, action));
// ... or ...
requestContext.HttpContext.Response.Redirect("/Some/Other/Url");
}
}
}

当通过Controller类派生控制器时,你可以使用同样的办法。上述在Execute方法中读取requestContext.HttpContext.Response属性时返回的是HttpResponseBase类,这个类在我们的派生控制器中可以直接通过Controller.Response属性进行使用,如清单12-8所示。

Listing 12-8. Using the Response Property to Generate Output

using System.Web.Mvc;
namespace ControllersAndActions.Controllers {
public class DerivedController : Controller {
public void Index() {
string controller = (string)RouteData.Values["controller"];
string action = (string)RouteData.Values["action"];
Response.Write(
string.Format("Controller: {0}, Action: {1}", controller, action));
// ... or ...
Response.Redirect("/Some/Other/Url");

}
}
}

这种办法是可以工作的,但它有几个问题:

· The controller classes must contain details of HTML or URL structure, which makes the classes harder to read and maintain.
控制器类必须含有HTML或URL结构的细节,这些使类难以阅读和维护。

· 把响应直接生成为输出的控制器难以进行单元测试。为了确定输出表示的是什么,你需要生成Response对象的模仿实现,然后才能处理你从控制器接收到的输出。例如,这可能意味着要解析HTML关键词,这是费时而痛苦的过程。

· 这种精细处理每个响应细节的方式是乏味而易错的。有些程序员喜欢对建立原始控制器的过程进行绝对控制,但大多数人很快就失败了。

幸运的是,MVC框架一个叫做动作结果的很好的特性解决了所有这些问题。以下小节介绍这个动作结果概念,并向你演示可以用它来生成控制器响应的不同方法。
理解动作结果

MVC框架通过使用动作结果把指明(stating)意图与执行(executing)意图分离开来。它工作起来十分简单。
不是直接用Response对象进行工作,而是返回派生于ActionResult类的一个对象,它描述我们希望控制器响应要做什么,例如,渲染一个视图、重定向到另一个URL或动作方法。

注意:动作结果系统是一种命令模式。这个模式描述你所处的场景并发送一些对象,这些对象描述了要执行的操作。更多细节参阅http://en.wikipedia.org/wiki/Command_pattern。
在面向对象编程中,命令模式是一种设计模式,在这个模式中,用一个对象来表示和封装之后要调用的方法所需要的所有信息。这些信息包括方法名、拥有这个方法的对象、以及该方法参数的值。

根据这一定义,我们可以这样来理解动作结果:动作结果是一种命令,它的目的是要执行一个方法。为了实现这种要执行一个方法的命令,我们需要形成一个对象,用这个对象来封装一些信息,这些信息包括目标方法名、包含该目标方法的对象、该目标方法所需要的参数等。

当MVC框架从一个动作方法接收一个ActionResult对象时,MVC框架调用由这个类所定义的ExecuteResult方法。然后该动作结果的实现为你处理这个Response对象,生成符合你意图的输出。一个简单的例子是清单12-9所示的RedirectResult类。MVC框架开源的好处之一是你可以看到场景背后的事情是如何进行的。我们简化了这个类,以使它易于阅读。

Listing 12-9. The System.Web.Mvc.RedirectResult Class

public class RedirectResult : ActionResult {
public RedirectResult(string url) : this(url, permanent: false) {
}
public RedirectResult(string url, bool permanent) {
Permanent = permanent;
Url = url;
}
public bool Permanent {
get;
private set;
}
public string Url {
get;
private set;
}
public override void ExecuteResult(ControllerContext context) {
string destinationUrl = UrlHelper.GenerateContentUrl(Url, context.HttpContext);
if (Permanent) {
context.HttpContext.Response.RedirectPermanent(destinationUrl,
endResponse: false);
}
else {
context.HttpContext.Response.Redirect(destinationUrl, endResponse: false);
}
}
}

当我们生成RedirectResult类的实例时,我们在其中传递了重定向用户的URL,以及(可选地)是否是永久还是临时重定向。ExecuteResult方法,它将在我们的动作方法完成时由MVC框架执行,通过框架提供的ControllerContext对象得到这个查询的Response对象,并调用RedirectPermanent或Redirect方法,这是我们在清单12-8中明确用手工做的事情。

UNIT TESTING CONTROLLERS AND ACTIONS
单元测试控制器与动作
MVC框架的许多部分都被设计成便于单元测试,特别是对控制器与动作。这种支持有几个原因:

· 你可以在一个web服务器之外测试控制器与动作。通过它们的基类(如HttpRequestBase)访问上下文对象,这易于模仿。

· 你不需要解析任何HTML来测试一个动作方法的结果。你可以检查所返回的ActionResult对象,以确保你接收了预期的结果。

· 你不需要模拟客户端请求。MVC框架的模型绑定系统允许你编写以方法参数接收输入的动作方法。要测试一个动作方法,你只要简单地直接调用该动作方法,并提供你感兴趣的参数值。

随着本书的进行,我们将向你演示如何生成各种动作结果的单元测试。
不要忘记,单元测试并不是事情的全部。当动作方法被依次调用时,会出现应用程序的复杂行为。单元测试最好与其它测试办法相结合。
我们可以使用这个RedirectResult类,通过在动作方法中生成RedirectResult的新实例并将其返回。清单12-10演示了我们的DerivedController类,它被更新成有两个动作方法,其中一个用RedirectResult把请求重定向到另一个。

Listing 12-10. Using the RedirectResult Class

using System.Web.Mvc;
namespace ControllersAndActions.Controllers {
public class DerivedController : Controller {
public void Index() {
string controller = (string)RouteData.Values["controller"];
string action = (string)RouteData.Values["action"];
Response.Write(
string.Format("Controller: {0}, Action: {1}", controller, action));
}
public ActionResult Redirect() {
return new RedirectResult("/Derived/Index");
}
}
}

如果你启动这个应用程序,并导航到/Derived/Redirect,你的浏览器将被重定向到/Derived/Index。为了使你的代码更简单,Controller类包含了用来生成各种ActionResults的一些便携方法。于是,例如通过返回Redirect方法的结果,我们可以取得清单12-10所示的效果,如清单12-11所示。

Listing 12-11. Using a Controller Convenience Method for Creating an Action Result

public ActionResult Redirect() {
return Redirect("/Derived/Index");
}

在动作结果系统中再没有其它复杂的东西了,你最终实现了更简单、更清晰、且更具一致性的代码。而且,你可以很容易地测试你的动作方法。例如,在这个重定向案例中,你可以简单地检查该动作方法返回了一个RedirectResult实例,以及Url属性含有你预期的目标。
MVC框架含有许多内建的动作结果类型,如表12-2所示。所有这些类型都派生于ActionResult,其中有不少在Controller类中有便利的辅助方法。

表2-2. 内建的ActionResult类型
Type
类型
Description
描述
Controller Helper Methods
控制器辅助方法
ViewResult 返回指定的或默认的视图模板 View
PartialViewResult 返回指定的或默认的局部视图模板 PartialView
RedirectToRouteResult 将HTTP 301或302重定向发送给一个动作方法或特定的路由条目,根据你的路由配置生成一个URL RedirectToAction
RedirectToActionPermanent
RedirectToRoute
RedirectToRoutePermanent
RedirectResult 将HTTP 301或302重定向发送给一个特定的URL Redirect
RedirectPermanent
ContentResult 把原始的文字数据返回给浏览器,可选地设置一个content-type(内容类型)头 Content
FileResult 直接把二进制数据(如磁盘文件或内存中的字节数组)传输给浏览器 File
JsonResult 序列化一个JSON格式的.NET对象,并把它作为响应进行发送 Json
JavaScriptResult 发送一个应当由浏览器执行的JavaScript源代码片段(这只是打算提供给AJAX场合使用的,在第19章中描述) JavaScript
HttpUnauthorizedResult 将响应的HTTP状态码设置为401(意为“未授权”),这会引发当前的认证机制(表单认证或Windows认证)来要求访问者登录 None
HttpNotFoundResult 返回一个HTTP 404 — 未找到错误 HttpNotFound
HttpStatusCodeResult 返回一个指定的HTTP码 None
EmptyResult 什么也不做 None

在以下小节中,我们将向你演示如何使用这些结果,以及如何生成和使用自定义动作结果。

通过渲染视图返回HTML

一个动作方法最常用的一种响应形式是生成HTML并把它发送给浏览器。当使用动作结果系统时,你通过生成一个ViewResult类的实例来做这件事,该实例指定你想渲染以生成这个HTML视图,当清单12-12所示。

Listing 12-12. Specifying a View to Be Rendered Using ViewResult

using System.Web.Mvc;
namespace ControllersAndActions.Controllers {
 public class ExampleController : Controller {
   public ViewResult Index() {
     return View("Homepage");
     }
   }
}

在这个清单中,我们使用View辅助方法来生成ViewResult类的一个实例,然后它作为该动作方法的结果被返回。
注意:返回类型是ViewResult。该方法被编译并运行,就好像我们已经指定了更一般的ActionResult类型一样。事实上,有些MVC程序员会把每个动作方法的结果都定义成ActionResult,即使他们知道该动作方法返回的是一个更特定的类型。在知道方法返回的类型时,我们更喜欢用最具体的类型,这是常规的面向对象约定。在以下的例子中,我们特别注重了这种实践,以使你清楚可以如何去使用每一种结果类型。
通过送给View方法的参数,你指定了你要渲染的视图。在这个例子中,我们已经指定了Homepage视图。
注意:我们可能明确地生成了ViewResult对象,(用return new ViewResult { ViewName = "Homepage" };)。这是一个完全可接受的办法,但我们更喜欢使用由Controller类所定义的便利辅助方法。
当MVC框架调用ViewResult对象的ExecuteResult方法时,将开始搜索你已经指定的视图。如果在你的项目中使用了区域,那么框架将查找以下位置:

· /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

你可以从上述列表看出,框架也查找了遗留视图引擎生成的视图(.aspx和.ascs文件扩展名),即使我们在生成该项目时指定的是Razor。框架也查找了C#和VB的.NET Razor模板(.cshtml文件为C#模板的,.vbhtml是VB的)。MVC框架依次检查这些文件是否存在。只要它定位到一个匹配,它就用这个视图来渲染该动作方法的结果。
如果你未使用区域,或者你使用了区域,但在前述列表中没找到文件,那么框架会使用以下的位置继续它的搜索:

· /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框架检测一个位置并找到一个文件,搜索便停止,已经找到的这个视图便被用来渲染响应到客户端。
在清单12-12中,我们未使用区域,因此框架查找的第一个位置将是/Views/Example/Index.aspx。注意,这个类名的Controller部分是被忽略的(意即,ExampleController的Controller被忽略 — 译者注),因此,在ExampleController中生成的ViewResult会导致对名为Example的目录的搜索。

UNIT TEST: RENDERING A VIEW
单元测试:渲染一个视图

To test the view that an action method renders, you can inspect the ViewResult object that it returns. This is not quite the same thing—after all, you are not following the process through to check the final HTML that is generated—but it is close enough, as long as you have reasonable confidence that the MVC Framework view system works properly.
为了测试一个动作方法渲染的视图,你可以检查它所返回的ViewResult对象。这并不是十分相同的事情 — 必竟,你并不是在通过查检最终生成的HTML来跟踪这一过程 — 但这也已经足够了,只要你有理由确信MVC框架视图系统能恰当地工作。
要测试的第一个情况是当动作方法选择了一个特定视图时,像这样:

public ViewResult Index() {
   return View("Homepage");
}

通过读取ViewResult对象的ViewName属性,你可以确定哪个视图被选中了,如以下测试方法所示:

[TestMethod]
public void ViewSelectionTest() {
  // Arrange - create the controller
  ExampleController target = new ExampleController();
  // Act - call the action method
  ActionResult result = target.Index();
  // Assert - check the result
  Assert.AreEqual("Homepage", result.ViewName);
}

当你测试选择了默认视图的动作方法时,稍有不同,像这样:

public ViewResult Index() {
   return View();
}

在这种情况下,你需要对视图名用空字符串,像这样:

Assert.AreEqual("", result.ViewName);

MVC框架搜索视图目录的顺序是“约定优于配置”这一规范的另一个例子(The sequence of directories that the MVC Framework searches for a view is another example of convention over configuration)。你不需要用框架来注册你的视图文件。只需要把它们放在一组已知位置的一个位置上,框架会找到它们。
提示:定位视图的命名约定是可定制的。我们将在第15章向你演示如何去做。
在我们调用View方法时,通过忽略待渲染视图名,我们可以使这个约定更进一步,如清单12-13所示。

Listing 12-13. Creating a ViewResult Without Specifying a View

using System.Web.Mvc;
namespace ControllersAndActions.Controllers {
   public class ExampleController : Controller {
      public ViewResult Index() {
         return View();
         }
      }
}

当我们这样做时,MVC框架假设我们想渲染的是一个与动作方法同名的视图。意即,清单12-13中对View方法的调用将启动对一个名字为Index的视图的搜索。

注意:其效果是一个与动作方法同名的视图被搜寻,但视图名实际上是根据RouteData.Values[“action”]的值所确定的,这就是你在清单12-7中以及在第11章路由系统部分所看到的情况。
View方法有许多重载版本。它们对应所创建的ViewResult对象上设置的不同属性。例如,通过明确地命名一个布局,你可以覆盖一个视图所使用的(默认)布局,像这样:

public ViewResult Index() {
   return View("Index""_AlternateLayoutPage");
}

译者注:在这个方法中,"_AlternateLayoutPage"参数给出的是布局文件名(不带扩展名),该布局应当是/View/Shared/文件夹中的_AlternateLayoutPage.cshtml文件。

SPECIFYING A VIEW BY ITS PATH
通过路径指定视图
命名约定的办法方便而简单,但它限制了你可以渲染的视图。如果你想渲染一个特定的视图,你可以通过提供一个明确的路径并绕过搜索阶段来做这件事。以下是一个例子:

using System.Web.Mvc;
namespace ControllersAndActions.Controllers {
  public class ExampleController : Controller {
    public ViewResult Index() {
      return View("~/Views/Other/Index.cshtml");
      }
    }
}

当你像这样指定了一个视图时,路径必须从/或~/开始,并包括文件扩展名(例如,.cshtml对应的是含有C#代码的Razor视图)。

如果你感到你要用这一特性(feature),我们建议你花一些时间,并自问一下你要达到什么结果。如果是试图渲染属于另一个控制器的视图,那么你也许最好把用户重向到那个控制器的一个动作方法(参见本章稍后“重定向到一个动作方法”小节的例子)。因为它不适合你项目的组织方式,如果你试图围绕命名方案进行工作,那么参见第15章,它解释了如何实现一个自定义搜索顺序。(这一小节的含义是你最好不要用这种办法直接指定视图,这不利于应用程序的进一步扩展和维护 — 译者注)

把数据从动作方法传递给视图

我们通常需要把数据从一个动作方法传递给一个视图。MVC框架提供了许多做这种事情的不同方式,我们将在以下小节中加以描述。在这些小节中,我们提及的关于视图的论题,将在第15章作深度讨论。在本章中,我们将只讨论足以演示我们感兴趣的控制器特性(features)所需要的视图功能性。

提供视图模型对象

你可以把一个对象作为View方法的参数,把这个对象发送给视图,如清单12-14所示。

Listing 12-14. Specifying a View Model Object

public ViewResult Index() {
   DateTime date = DateTime.Now;
   return View(date);

}

我们已经传递了一个DateTime对象作为视图模型。我们可以在视图中用Razor的Model关键词来访问这个对象,如清单12-15所示。

Listing 12-15. Accessing a View Model in a Razor View

@{
  ViewBag.Title = "Index";
}
<h2>Index</h2>
The day is: @(((DateTime)Model).DayOfWeek)

清单12-15所示的视图称为非类型或弱类型视图。该视图不知道关于视图模型对象的任何事情,而把它作为对象的一个实例来看待。为了得到DayOfWeek属性的值,我们需要把这个对象转换成DateTime的一个实例。这可以工作,但会产生杂乱的视图。我们可以通过生成强类型视图加以整理,在强类型视图中,我们告诉视图,视图模型对象将是什么类型,如清单12-16所示。

Listing 12-16. A Strongly Typed View

@model DateTime
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
The day is: @Model.DayOfWeek

我们用Razor的model关键词指定了视图的模型类型。注意,当我们指定模型类型时,使用小写的m,而在读取值时使用大写的M。这样做不仅便于整洁我们的视图,而且Visual Studio对强类型视图支持智能感应,如图12-3所示。

12-3. 支持强类型视图的智能感应

UNIT TEST: VIEW MODEL OBJECTS
单元测试:视图模型对象

你可以通过ViewResult.ViewData.Model属性来访问从动作方法传递给视图的视图模型对象。以下是一个简单的动作方法:

 

public ViewResult Index() {
   return View((object)"Hello, World");
}

 

 该动作方法传递一个字符串作为视图模型对象。我们已经把它转换成object,以便编译器不会认为我们想用的是指定视图名的那个View重载。我们可以通过ViewData.Model属性来访问这个视图模型,如以下测试方法所示:

[TestMethod]
public void ViewSelectionTest() {
// Arrange - create the controller
ExampleController target = new ExampleController();
// Act - call the action method
ActionResult result = target.Index();
// Assert - check the result
Assert.AreEqual("Hello, World", result.ViewData.Model);
}

 ViewBag传递数据

在第3章中我们介绍过View Bag(视图包)特性(feature)。该特性允许你在一个动态对象上定义任意属性,并在视图中访问它们。这个动态对象可以通过Controller.ViewBag属性进行访问,如清单12-17所示。

Listing 12-17. Using the View Bag Feature

public ViewResult Index() {
   ViewBag.Message = "Hello";
   ViewBag.Date = DateTime.Now;

   return View();
}

 在该清单中,我们通过简单赋值的办法,已经定义了名为Message和Date的属性。在此之前这些属性是不存在的,我们不做任何准备地生成了它们。要在视图中读回这些数据,我们简单地采用在动作方法中设置的同样的属性,如清单12-18所示。

Listing 12-18. Reading Data from the ViewBag

 

@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
The day is: @ViewBag.Date.DayOfWeek
</>
The message is: @ViewBag.Message

 

 ViewBag相对于使用一个视图模型对象有一个优点:它便于把多个对象发送给视图。如果我们只能使用视图模型,那么,为了获得清单12-17和12-18的同样效果,我们就需要生成一个新类型,它具有string和DateTime成员。

当用动态对象进行工作时,你可以在视图中调用方法和属性的任意序列,像这样:

The day is: @ViewBag.Date.DayOfWeek.Blah.Blah.Blah

Visual Studio不能提供对任何动态对象的智能感应支持,包括ViewBag,而且在视图被渲染之前不支持诸如“对此无法展示”之类的错误提示。

提示:我们喜欢ViewBag的灵活性,但我们倾向于使用强类型视图。在同一个视图中既使用视图模型也使用View Bag是没有限制的。它们两者可以无干扰地一起工作。

UNIT TEST: VIEWBAG
单元测试ViewBag

你可以通过ViewResult.ViewBag属性读取ViewBag的值。以下测试方法是针对清单12-17中动作方法的测试:

[TestMethod]
public void ViewSelectionTest() {
// Arrange - create the controller
ExampleController target = new ExampleController();
// Act - call the action method
ActionResult result = target.Index();
// Assert - check the result
Assert.AreEqual("Hello", result.ViewBag.Message);
}

 View Data传递数据

View Bag特性(feature)是随MVC的第3版引入的。在此之前,用视图模型对象的替代方案主要是View Data。View Data(视图数据)特性(feature)类似于View Bag,但它是用ViewDataDictionary类不是动态对象实现的。ViewDataDictionary类似于规则的“键/值”集合,并通过Controller类的ViewData属性进行访问,如清单12-19所示。

Listing 12-19. Setting Data in the ViewData Class

public ViewResult Index() {
   ViewData["Message"] = "Hello";
   ViewData["Date"] = DateTime.Now;
   return View();
}

 就像使用“键/值”集合那样,你可以在视图中读回这些数据值,如清单12-20所示。

Listing 12-20. Reading View Data in a View

@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
The day is: @(((DateTime)ViewData["Date"]).DayOfWeek)
</>
The message is: @ViewData["Message"]

 你可以看出,我们必须对从视图数据获得的对象进行转换,这十分类似于我们对非类型视图所做的那样。

注意:在View Bag可用的情况下,我们现在不太喜欢View Data了。

UNIT TEST: VIEW DATA
单元测试:View Data

通过读取ViewResult.ViewData的值,你可以测试使用View Data的动作方法。以下测试是用于清单12-19中的动作方法的:

[TestMethod]
public void ViewSelectionTest() {
// Arrange - create the controller
ExampleController target = new ExampleController();
// Act - call the action method
ActionResult result = target.Index();
// Assert - check the result
Assert.AreEqual("Hello", result.ViewData["Message"]);
}

 执行重定向

一个动作方法的通常结果并不是直接产生输出,而是把用户的浏览器重定向到另一个URL。大多数情况下,这个URL是应用程序中的另一个动作方法,它生成你希望用户看到的输出。

POST/Redirect/GET模式

重定向最经常的应用是用在处理HTTP POST请求的动作方法中。正如我们在上一章所提到的,当你希望修改应用程序状态时,才会使用POST请求。如果你只是简单地在请求处理之后马上返回HTML,你就陷入这样的风险:用户点击浏览器的重载按钮(意指“刷新当前页面” — 译者注),并再次递交该表单、引发异常及不符需求的结果。

为了避免这种问题,你可以遵循Post/Redirect/Get模式。在这个模式中,你接收一个POST请求、处理它、然后重定向浏览器,以便由浏览器形成另一个GET请求的URL。GET请求不会修改你应用程序的状态,因此,该请求的任何不经意的再次递交都不会引起任何问题。

在执行重定向时,给浏览器发送的是以下两个HTTP代码之一:

· 发送HTTP代码302,这是一个临时重定向。这是最常用的重定向类型,而且直到MVC 3,这是MVC框架内建支持的唯一的一种重定向。当使用Post/Redirect/Get模式时,这是你要发送的代码。

· 发送HTTP代码301,它表示一个永久重定向。应该小心地使用它,因为它指示HTTP代码接收器不要再次请求原始URL,并使用包含重定向代码所伴随的新URL。如果你有疑问,请使用临时重定向,即,发送代码302。

重定向到字面(LiteralURL

重定向浏览器最基本的方式是调用Redirect方法,它返回RedirectResult类的一个实例,如清单12-21所示。

Listing 12-21. Redirecting to a Literal URL

public RedirectResult Redirect() {
   return Redirect("/Example/Index");
}

你要重定向的URL应当表示成一个字符串,并作为传递给Redirect方法的参数。Redirect方法发送一个临时重定向。你可以用RedirectPermanent方法发送一个永久重定向,如清单12-22所示。

Listing 12-22. Permanently Redirecting to a Literal URL

public RedirectResult Redirect() {
   return RedirectPermanent("/Example/Index");
}

提示:如果你喜欢,你可以用Redirect方法的重载版本,它以一个布尔型参数指定是否永久重定向。

UNIT TEST: LITERAL REDIRECTIONS
单元测试:字面重定向

字面重定向易于测试。你可以用RedirectResult类的Url和Permanen属性来读取URL以及该重定向是永久的还是临时的。以下是清单12-21重定向的一个测试方法。

[TestMethod]
public void RedirectTest() {
// Arrange - create the controller
ExampleController target = new ExampleController();
// Act - call the action method
RedirectResult result = target.Redirect();
// Assert - check the result
Assert.IsFalse(result.Permanent);
Assert.AreEqual("/Example/Index", result.Url);
}

重定向到路由系统的一个URL

如果你要把用户重定向到应用程序的一个不同的部分,你需要确保你发送的URL符合之前章节所描述的URL模式。用字面URL进行重定向的问题是,对路由方案的任何修改,都意味着你需要检查你的代码,并对URL进行更新。

一种可选的替代办法是,你可以运用路由系统,以RedirectToRoute方法来生成有效的URL,该方法会生成RedirectToRouteResult的一个实例,如清单12-23所示。

Listing 12-23. Redirecting to a Routing System URL

public RedirectToRouteResult Redirect() {
return RedirectToRoute(new {
controller = "Example",
action = "Index",
ID = "MyID"
});
}

RedirectToRoute方法发布一个临时重定向。对于永久重定向,使用RedirectToRoutePermanent方法。这两个方法都以一个匿名类型为参数,其属性然后被传递给路由系统,以生成一个URL。此过程的更多细节请参阅第11章的“生成输出URL”小节。

UNIT TESTING: ROUTED REDIRECTIONS
单元测试:路由的重定向

以下是测试清单12-23动作方法的示例:

[TestMethod]
public void RedirectValueTest() {
// Arrange - create the controller
ExampleController target = new ExampleController();
// Act - call the action method
RedirectToRouteResult result = target.Redirect();
// Assert - check the result
Assert.IsFalse(result.Permanent);
Assert.AreEqual("Example", result.RouteValues["controller"]);
Assert.AreEqual("Index", result.RouteValues["action"]);
Assert.AreEqual("MyID", result.RouteValues["ID"]);
}

重定向到一个动作方法

通过使用RedirectToAction方法,你可以更雅致地重定向到一个动作方法。这只是RedirectToAction方法一个封装程序,让你指定动作方法和控制器的值,而不需要生成一个匿名类型,如清单12-24所示。

Listing 12-24. Redirecting Using the RedirectToAction Method 

public RedirectToRouteResult Redirect() {
  return RedirectToAction("Index");
}

如果你只指定一个动作方法,那么它假设你指向的是当前控制器的一个动作方法。如果你想重定向到另一个控制器,你需要以参数提供其名字,像这样:

return RedirectToAction("Index", "MyController");

还有一些其它的重载版本,你可以用来为URL生成提供额外的值。这些版本是用一个匿名类型来表示的,这有点破坏了便携方法,但仍然能使你的代码易于阅读。

注意:你为控制的动作方法所提供的值,在它们被传递给路由系统之前,是不会被检验的。你有责任要确保你所指定的目标是实际存在的。

RedirectToAction方法执行一个临时重定向。用RedirectToActionPermanent进行永久重定向。

PRESERVING DATA ACROSS A REDIRECTION
跨越重定向保留数据

重定向引发浏览器递交一个全新的HTTP请求,这意味着你没有访问原始请求的细节。如果你希望把一个请求的数据传递给下一个请求,你可以用Temp Data特性。

TempData类似于Session数据,只不过,TempData的值在被读取之后,被标记为删除,并在该请求已经被处理之后被删除。这对于你跨越重定向而保留的短期数据是一种理想的安排。以下是使用了RedirectToAction方法的一个简单的动作方法:


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
《ASP.NET Core 与 RESTful API 开发实战》-- (第8章)-- 读书笔记(中) ...发布时间:2022-07-10
下一篇:
asp.net文件上传类发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap