1

我一直在努力通過在我的Web應用程序中實現IoC的細節,但是以利用Microsoft.Practices.ServiceLocation的方式。我特別使用Autofac和asp.net集成,但我想讓自己開放給其他容器。沿着this question的路線,我很擔心如何訪問我的Web應用程序代碼中的容器。Autofac,ASP.NET和Microsoft.Practices.ServiceLocation

我有一個'核心'庫,主要定義要解決的接口。這個核心庫也被我的網絡應用和其他應用使用。非常方便定義通用接口。我認爲這是訪問IoC容器的好地方,而且我是用靜態類來做的。訣竅是將容器注入靜態類。

由於每個請求的容器可能不同,因此在Web環境中很棘手,而在非Web應用程序中,它可能會始終保持不變。起初我嘗試用方法注入容器direclty,但很快就在下一個Web請求中失敗!所以,我想出了這個:

public static class IoCContainer 
{ 
    public static void SetServiceLocator(Func<IServiceLocator> getLocator) 
    { 
     m_GetLocator = getLocator; 
    } 
    static private Func<IServiceLocator> m_GetLocator = null; 

    public static T GetInstance<T>(string typeName) 
    { 
     return m_GetLocator().GetInstance<T>(typeName); 
    } 
} 

現在,在我的global.asax.cs我這樣做:

protected void Application_Start(object sender, EventArgs e) 
{ 
    var builder = new Autofac.Builder.ContainerBuilder(); 
    ... register stuff ... 
    var container = builder.Build(); 
    _containerProvider = new Autofac.Integration.Web.ContainerProvider(container); 
    Xyz.Core.IoCContainer.SetServiceLocator(() => 
     new AutofacContrib.CommonServiceLocator.AutofacServiceLocator 
      (_containerProvider.RequestContainer)); 
} 
public IContainerProvider ContainerProvider 
{ 
    get { return _containerProvider; } 
} 
static IContainerProvider _containerProvider; 

,並呼籲解決的依賴性看起來像

var someService = Xyz.Core.GetInstance<ISomeService>(); 

因此,而不是傳遞一個特定的容器,我傳遞一個知道如何獲取容器的委託。對於非web應用程序,委託人可能會返回builder.Build()提供的內容。

我向專家提出的問題是,這是否有意義?我有一個簡單的方法可以找到可以解決依賴關係的問題,而無需知道容器產品是什麼或容器本身來自哪裏。你怎麼看?

回答

2

我們使用類似的模式,主要是因爲IoC被引入非DI架構。因此,需要能夠顯式調用容器來獲得服務,這基本上是工廠模式。

當所有依賴關係都可以被注入並且您的代碼不再依賴於服務定位符時,IoC的真正好處就可以實現。 Autofac.Integration.Web有處理程序將執行注入您的頁面對象,這將使靜態服務定位器過時。伊莫這是首選的方式,但(在我們的情況下)服務定位不能總是避免。

也就是說,既然您已經使用IoCContainer類將您的應用程序從容器中分離出來,我沒有理由在IoCContainer中添加AutofacServiceLocator的附加抽象。底線是IoCContainer已經是你的服務定位器,應該被允許直接訪問容器實現。

這是我對你的服務定位器類:

public static class IoCContainer 
{ 
    private static IContext GetContainer() 
    { 
     var cpa = 
      (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance; 
     return cpa.ContainerProvider.RequestContainer; 
    } 

    public static T GetInstance<T>() 
    { 
     return GetContainer().Resolve<T>(); 
    } 
} 
+0

這是非常酷的彼得,但我希望能夠重用我的「核心」庫在其他情況下,甚至沒有基於網絡。不過,我認爲這是一個很好的答案,因爲它有助於我避免太多的抽象。謝謝! – n8wrl 2009-10-08 13:51:34

+0

我明白你的觀點。儘管如此,如果你完全可以不使用服務定位器模式,而只使用依賴注入,你根本不需要解決這個問題:) – 2009-10-08 15:18:24