2009-07-15 51 views
31

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

是你无法使用:HttpContext.Items
在本节 上面,我们来到干净,告诉你,我们对你撒谎:HttpContext的是不是ASP之间共享.NET MVC和ASP.NET Web窗体。因此,您不能使用HttpContext.Items集合来存储和检索多个数据。

这样做的原因是因为一旦您重定向到一个控制器,你的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,我已经改变了指数的方法:

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

,并改变了关于方法:

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

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

所以,在我看来,就好像我要么不理解什么书意义,当他们说 “之类的东西HttpContext.Items不会转移”或它传递这个东西,也没关系使用的HttpContext。项目。

如果你们推荐我避免HttpContext.Items,有没有存放在每个请求的基础跨请求对象的另一个替代方式?

+0

这是创建一个“应用程序上下文”类型的对象非常有用的资源:http://jcapka.blogspot.co.uk/2013/11/creating-application-context-for-net.html – JDandChips 2015-03-12 09:31:04

回答

35

你的问题是要求一些事情,但我认为项目#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请求。首先是索引操作被调用时。第二种是当调用RedirectToAction动作时(它是一个HTTP 302)。要使其失败,请在Index操作中设置一个新值,并查看它是否保留在关于操作中。

3

使用TempData的字典,它主要是为操作间存储对象重定向:

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

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

然后在您的视图检索值:

<%=ViewData["Test"] %> 
+3

感谢您的答案,但我不想使用会话状态。这是因为我的应用程序可能正在Web场下运行,并且会话状态的性能在用完时不好。 (TempData将它的值存储在SessionState中) – 2009-07-15 23:25:01

1

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

+1

它实际上*是*性能影响。如果你运行一个Web服务器场,你需要在整个服务器场中共享会话(因为在一个请求中你可能会访问服务器A,然后在* next *请求中你可能会被路由到服务器B)。这通常是使用SQL Server会话提供程序完成的,与进程相比,它非常慢并且很糟糕。这是如此缓慢和蹩脚,每个人都应该避免与一个10英尺的杆。或者,如果你有一些方便的话;)。 – 2009-07-16 05:08:47

+0

同样,即使在TempData中存储对象也会使它跨越请求。我不想那样。我只想为当前请求存储它。 – 2009-07-16 05:09:33