2009-07-15 77 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