36

我正在使用我自己的使用单例模式的 ApplicationContext 类。我想将它的实例存储在 HttpContext.Items 中,因为它可以在请求的所有部分中访问。我一直在阅读有关将 HttpContext 与 ASP.NET MVC 结合使用的信息,主要的痛点之一是它引入了测试复杂性。我试过研究 HttpContext.Items 的可测试性,但我能找到的只是 Session 上的东西。我发现的唯一内容之一是关于 Wrox 的 Professional ASP.NET 3.5 MVC 书的示例章节(此处为 pdf 链接)。在第 15 页上,它说:

你不能使用的东西:HttpContext.Items
在本节的上面,我们坦白告诉你我们对你撒了谎:HttpContext 不在 ASP.NET MVC 和 ASP.NET Web 窗体之间共享。因此,您不能使用 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。写入 global.asax.cs 中设置的正确“Hello World”字符串。

因此,在我看来,当他们说“未传输 HttpContext.Items 之类的东西”时,我似乎要么不理解这本书的含义,要么它确实传输了这些东西,并且可以使用 HttpContext.Items。

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

4

3 回答 3

41

你的问题是问一些事情,但我认为第 1 项是你正在寻找的答案。

  1. Context.Items在每个请求的基础上用于缓存是否可以?是的。如果在处理中、每个请求、网络场中的每台机器是您的标准,那么 Context.Items 会为您提供。

  2. Context.Items很难测试吗?就可测试性而言,我会隐藏Context.Items在某种接口后面。通过这种方式,您无需Context.Items直接引用即可获得单元测试功能。否则,你需要测试什么Context.Items?该框架将存储和检索值?让您的代码一无所知,System.Web您将成为一个快乐的露营者。

  3. Context.Items活下来RedirectToAction吗?不,您的测试无效。它在每个 Web 请求上设置“Hello, world”,您的测试跨越两个 Web 请求。第一个是调用 Index 操作时。第二个是RedirectToAction调用操作时(它是 HTTP 302)。要使其失败,请在 Index 操作中设置一个新值,并查看它是否保留在 About 操作中。

于 2009-07-16T06:14:47.553 回答
4

使用 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"] %>
于 2009-07-15T23:00:50.980 回答
1

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

于 2009-07-16T01:51:25.517 回答