2012-07-30 61 views
4

我想在Web應用程序中使用AutoFac。我有根容器,每個會話有一個子容器,每個請求有一個子容器。我試圖找出管理這些生命週期範圍的最佳方法。在Global.asax.cs中我已經添加了以下內容:在asp.net中管理每個會話和請求的AutoFac生命週期範圍mvc 3

protected void Application_Start(object sender, EventArgs e) 
{ 
    var container = ...; 
} 

protected void Session_Start(object sender, EventArgs e) 
{ 
    var sessionScope = container.BeginLifetimeScope("session"); 

    Session["Autofac_LifetimeScope"] = sessionScope; 
} 

protected void Application_BeginRequest(object sender, EventArgs e) 
{ 
    var sessionScope = (ILifetimeScope) Session["Autofac_LifetimeScope"]; 
    var requestScope = sessionScope.BeginLifetimeScope("httpRequest"); 

    HttpContext.Current.Items["Autofac_LifetimeScope"] = requestScope; 
} 

protected void Application_EndRequest(object sender, EventArgs e) 
{ 
    var requestScope = (ILifetimeScope)HttpContext.Current.Items["Autofac_LifetimeScope"]; 
    requestScope.Dispose(); 
} 

protected void Session_End(object sender, EventArgs e) 
{ 
    var sessionScope = (ILifetimeScope)Session["Autofac_LifetimeScope"]; 

    sessionScope.Dispose(); 
} 

protected void Application_End(object sender, EventArgs e) 
{ 
    container.Dispose(); 
} 
  1. 我怎麼能告訴AutoFac用我的requestScope爲出發點越來越依賴關係,讓我註冊爲InstancePerLifetimeScope的實現將是使用我的requestScope解決?

  2. 如果這是不可能的,我可以讓AutoFac創建它的per-request生存期範圍嗎?

  3. 或者我在錯誤的軌道上嗎?有沒有其他的方法讓AutoFac知道這個層次結構?

任何幫助或其他意見表示讚賞。


迴應史蒂文。

我仍然在原型的早期階段,但有可能的事情,你可以有在sessionScope:

  • 使用UserPreferences
  • 身份驗證和授權範圍內(例如,用戶身份和角色)

與我將要構建的應用程序無關,但在電子商務環境中,購物車可以是會話範圍。這可能是最好的具體例子。這是你期望壽命比請求更長的事情,但比應用程序更短。

可能還有更多,但如果我有UserPreferences,Authentication和Authorization的策略,那麼這個策略也可以應用到稍後創建的其他組件。

可能的替代方法是在請求開始時獲取所有必要的信息,並將這些配置的組件放在請求範圍中。它會給我我期望的結果,但它與我在腦海中關於應用程序 - >會話 - >請求層次結構的模型不匹配。我希望創建一個合理的系統,因爲我絕對不是要維護它的系統。

+0

您希望在每個會話範圍註冊哪些服務?這對於我們在問題3「我在錯誤的軌道上嗎?」給出了一個很好的答案是需要的。 – Steven 2012-07-31 20:16:49

回答

11

你需要做的是實現你自己的Autofac.Integration.Mvc.ILifetimeScopeProvider。該接口管理如何/在哪裏生成請求生存期範圍。缺省值Autofac.Integration.Mvc.RequestLifetimeScopeProvider按照每個請求處理生命週期範圍的創建,處理和維護。

You can browse the code for RequestLifetimeScopeProvider here,如果您打算進行此操作,我強烈建議您這樣做。這是我能想到的最好的示例,其中包含顯示這些事情之一的責任的工作代碼。

您的實施ILifetimeScopeProvider將抓取會話子容器,從中產生請求容器,並在請求結束時清理請求容器。如果不存在,您可能還想在其中創建會話容器。處理會話容器的清理/處理可能會非常棘手,但從設計的角度來看,如果它們全都在一個地方,而不是提供者中的某些地方,那麼應用程序類中的某些地方會更好。

一旦你有你的ILifetimeScopeProvider你會設置你的依賴解析器時使用它。

var scopeProvider = new MyCustomLifetimeScopeProvider(container, configAction); 
var resolver = new AutofacDependencyResolver(container, scopeProvider); 
DependencyResolver.SetResolver(resolver); 

一對夫婦的警告有關的會話級範圍的概念的話:

  1. 你的內存佔用量是巨大的。您將最終爲系統中的每個用戶提供生命週期範圍。雖然請求生命期很快就會彈出並消失,但這些會話級作用域可能會存在很長時間。如果你有很多會話範圍的項目,你將有一個相當不錯的內存使用量爲每個用戶。如果人們在沒有正確註銷的情況下「放棄」他們的會話,那麼這些事情就會持續下去。
  2. 終身範圍及其內容不可序列化Looking at the code for LifetimeScope,它沒有標記爲[Serializable] ......即使是這樣,生活在那裏的解析對象也不一定都是標記爲可序列化的。這很重要,因爲這意味着您的會話級生存期範圍可能在具有內存中會話的單個框上工作,但是如果您使用SQL會話或會話服務部署到服務器場,則事情將分崩離析,因爲會話無法序列化您的存儲範圍。如果你選擇不序列化範圍,那麼你在每臺機器上的每個用戶都有不同的範圍 - 這也是一個潛在的問題。
  3. 會話不總是被重新水化。如果正在訪問的處理程序(如Web表單)未實現IRequiresSessionState,則會話將不會被重新組合(不管它是否處於進程中)。 Web表單和MvcHandler實現默認情況下,所以你不會看到任何問題,但如果你有需要注入的自定義處理程序,你會遇到一些障礙,因爲這些請求不存在「會話」。
  4. Session_End並不總是激發Per the docs on SessionStateModule.End,如果你使用out-of-proc會話狀態,你實際上不會得到Session_End事件,所以你將無法清理。

鑑於這些限制,通常儘量遠離會話存儲範圍。但是......如果這就是你要做的事情,那麼ILifetimeScopeProvider就是這樣做的。

+0

Nicholas Blumhardt在CodeProject上發表了一篇文章[描述這個層次結構](http://www.codeproject.com/Articles/25380/Dependency-Injection-with-Autofac#using-scope-to-control-visibility)。但那篇文章只是給出了一些不好的建議?我可以想象會有一些組件與會話具有相同的生命週期,所以它看起來是一個很好的方法。應用程序不會有很多用戶,並且不需要將其部署到場中。但你提出了一些有效的觀點。 – Jeroen 2012-07-31 08:10:58

+0

而2b,當擴展到Web場時,您的應用程序中將會出現內存泄漏,因爲在使用out-pro-pro會話狀態時,Session_End永遠不會被調用。 – Steven 2012-07-31 13:53:58

+0

在那篇文章中,我不認爲尼克是「提供建議」,而是使用session來提供更具體的例子來解釋嵌套層次結構如何工作。 – 2012-07-31 15:01:12