带有ASP.NET MVC的HttpContext.Items

时间:2009-07-15 22:19:55

标签: asp.net-mvc httpcontext

我正在使用单例模式我自己的ApplicationContext类。我想将它的实例存储在HttpContext.Items中,因为它可以在请求的所有部分中访问。我一直在阅读将HttpContext与ASP.NET MVC一起使用,其中一个主要问题是它引入了测试复杂性。我已经尝试过对HttpContext.Items的可测试性进行研究,但我能找到的就是Session上的内容。我发现的唯一一件事是在Wrox(pdf link here)上的Professional ASP.NET 3.5 MVC书中的示例章节之外。在第15页,它说:

  

你不能使用的东西:HttpContext.Items
  在本节的上方,我们清理过来并告诉您我们欺骗了您:ASP.NET MVC和ASP.NET Web窗体之间不共享HttpContext。因此,您无法使用HttpContext.Items集合来存储和检索数据位。

  这是因为一旦你重定向到一个Controller,你的HttpHandler就变成了System.Web.Mvc.MvcHandler,它是使用HttpContextWrapper创建的,它将有自己的HttpContext.Current定义。不幸的是,在握手期间,HttpContext.Items之类的东西不会被转移。

  这归结为HttpContext类型,尽管看起来和听起来非常相似,但是不一样,并且你不能以这种方式传递数据。

现在,我已经尝试过对此进行测试,据我所知,如果使用RedirectToAction重定向到另一个控制器,HttpContext.Items仍会保留。我正在使用默认的ASP.NET MVC项目来测试它。我所做的是,将此方法添加到Global.asax.cs:

protected void Application_BeginRequest()
{
    Context.Items["Test"] = "Hello World";
}

在HomeController.cs中,我已将Index方法更改为:

public ActionResult Index()
{
    return RedirectToAction("About");
}

并将About方法更改为:

public ActionResult About()
{
    Response.Write(Convert.ToString(HttpContext.Items["Test"]));
    return View();
}

当我运行应用程序时,页面正确地重定向到/ Home / About和Response.Writes在global.asax.cs中设置正确的“Hello World”字符串。

所以,在我看来,好像我要么不明白这本书的含义  “像HttpContext.Items这样的东西不会被转移”或者它确实传输了这些东西,并且可以使用HttpContext.Items。

如果你们建议我避免使用HttpContext.Items,是否有另一种方法可以在每个请求的基础上在请求中存储对象?

3 个答案:

答案 0 :(得分:38)

您的问题是提出一些问题,但我认为第1项是您正在寻找的答案。

  1. 在每个请求的基础上使用Context.Items进行缓存是否可以? 是。如果正在处理中,每个请求,Web场中的每台计算机都是您的标准,那么Context.Items会为您提供该标准。

  2. Context.Items难以测试吗? 至于可测试性,我会将Context.Items隐藏在某种界面后面。这样您就可以获得单元测试功能,而无需直接引用Context.Items。否则,您需要测试Context.Items的哪些内容?框架将存储和检索值?保持你的代码不知道System.Web,你将成为一个快乐的露营者。

  3. Context.ItemsRedirectToAction生存吗? 不,您的测试无效。它在每个Web请求上设置“Hello,world”,并且您的测试跨越了两个Web请求。第一个是调用Index操作的时候。第二个是调用RedirectToAction动作时(它是HTTP 302)。要使其失败,请在“索引”操作中设置一个新值,并查看它是否保留在“关于”操作中。

答案 1 :(得分:3)

使用TempData Dictionary,它主要用于在Actions重定向之间存储对象:

public ActionResult Index()
{
    TempData.Add("Test", "Hello world");
    return RedirectToAction("About");
}

public ActionResult About()
{
    ViewData["Test"] = TempData["Test"];
    return View();
}

然后检索视图中的值:

<%=ViewData["Test"] %>

答案 2 :(得分:1)

我做了一个测试,TempData确实在禁用会话状态时爆炸。我唯一的建议是不将对象本身存储在临时数据中,而是存储已建议的简单类型字段。由于您没有序列化对象树,因此不应该在运行过程中产生大的性能影响。