2011-01-10 45 views
2

在Microsoft Unity IoC中,如果我打電話給Resolve<SomeType>(),我可以保證返回的對象是在當前會話期間創建的對象嗎?是否解決<T>()每會話返回對象?

例如,三個用戶登錄,並讓我們說,是被在容器中創建的SomeType對象必須爲每個用戶不同的值。將調用Resolve返回爲當前用戶創建的對象嗎?或者它會做一些愚蠢的事情,比如返回創建的最後一個?

由於一些環境問題,我有麻煩測試自己,我需要很快檢查一些東西,所以如果有人能回答這個問題,這將是非常有益的!

編輯

原諒我,我是很新的團結,但基於what I read here,好像我應該能夠用唯一的名稱來註冊在容器中的對象,並通過該名稱進行檢索。那麼,我是不是可以使用會話ID或某個會話內持續存在的其他值來檢索我的對象?

+0

看起來好像你想使用Unity作爲緩存,如果你正在註冊一個'鑰匙'的實例。這實際上並不是Unity最擅長的\,也可能是您收到的答案令人困惑的原因。 – 2011-01-11 19:22:24

+1

如果你確實使用Unity作爲緩存,當你有一個Web服務器場時會發生什麼,或者當ASP.Net工作者進程再循環時會發生什麼? – 2011-01-11 19:32:31

+0

除了@chibacity說了什麼之外,如果你在不同的線程之間共享實例,那麼你正打開一個讓自己受到傷害的世界。哪個線程爲特定的請求提供服務是完全不確定的,並且當您想要訪問它時,您需要同步左側和右側中心。真的,創造新的對象,如果它需要去數據庫旅行並不昂貴。 – 2011-01-11 22:41:54

回答

6

哦,哇,在MVC應用程序中使用Unity的生命週期管理。我從哪說起呢?

首先,會話單例不是真的可行,因爲沒有ASP.NET系統可以保證在同一個會話中的請求之間使用同一個實例。會話可以通過在請求之間對其進行序列化和反序列化來模仿會話中保存的同一對象。

瞬態實例 - 即無需生命週期管理規範的簡單註冊在99%的時間內就足夠了。這意味着每次需要時都會創建一個註冊類型的實例。

您很少需要實例來貫穿請求的整個生命週期。但是,當你需要那些,你真的需要那些。與數據庫的連接是完美的選擇。另一方面,請求單身人士更容易創建和管理。

最優雅的解決方案是使用Unity的子容器功能。子容器可以在請求開始時創建,在請求結束時處理(作爲額外的獎勵,它將處置所有ContainerControlledLifetimeManager實例)。

創建子容器時,所有註冊仍然可以從父容器中獲得,因此您需要向子容器註冊請求特定的東西。

這裏是僞代碼得到這個工作:

private void Application_Start() { 
    _parentContainer = new UnityContainer(); 
    //creates a transient registration, available at any point in the app. 
    _parentContainer.RegisterType<IParentIntf, ParentIntfImpl>(); 
    ControllerBuilder.Current.SetControllerFactory(new ServiceLocatorControllerFactory()); 
} 

private void Application_BeginRequest() { 
    var childContainer = _parentContainer.CreateChildContainer(); 
    //registers a request "singleton" 
    //This registration is a type registration, an instance of RequestInterfaceImpl 
    //will be created when needed and then kept in the container for later use. 
    childContainer.RegisterType<IRequestInterface,RequestInterfaceImpl>(new ContainerControlledLifetimeManager()); 
    //save the child container in the context, so we can use it later 
    HttpContext.Items["childContainer"] = childContainer; 
} 

private void Application_EndRequest() { 
    //dispose the child container 
    ((IUnityContainer)HttpContext.Items["childContainer"]).Dispose(); 
} 

需要做的另一件事是重寫器廠使用子容器創建控制器。控制器是進入應用程序的第一個入口,它們可以簡單地依賴構造函數中的其他組件。

public class UnityControllerFactory : DefaultControllerFactory { 

    #region IControllerFactory Members 

    public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) { 
     IController controller; 
     controllerName = controllerName.ToLower(); 
     var container = ((IUnityContainer)HttpContext.Items["childContainer"]) 
     if(container.IsRegistered<IController>(controllerName)) 
      controller = container.Resolve<IController>(controllerName); 
     else 
      controller = base.CreateController(requestContext, controllerName) ; 
     return controller; 
    } 
} 
2

默認行爲是爲每個解析調用返回一個新實例,這不是你想要的。

在會話中創建和解析同一個實例是可能的,但據我所知沒有內置支持。你將不得不編寫自己的一生經理,然後在註冊你的類型時使用它。

有一個可以爲每個線程實例執行的生命週期管理器,但是這對於會話沒有用,因爲線程將被重用,並且解決方案還需要跨多個請求工作才能真正實現會話範圍。

有人爲此寫了一輩子的經理是完全可能的。