3

我已經在這個主題上好幾個小時了,所以我決定編寫並尋求一些幫助。注入不同的項目/裝配

在這個論壇上已經有很多答案可以認定是解決我的問題的方法,但我無法將我腦海中的所有點連接起來;我沒有完成它。

我試圖改變一個大的MVC應用程序,從StructureMap到SimpleInjector的注入器。

我需要正確地將HttpContext的當前用戶傳遞給同一個解決方案上的另一個項目,該解決方案包含所有存儲庫和DBContext,以便在執行一些CRUD操作時可以使用/寫入它。

我明顯不明白StructureMap是如何連線的;我發現它很複雜。我有這樣的MVC項目(可以提供更多的信息,因爲有一個使用StructureMap類打):

public class GlobalRegistry : StructureMap.Registry 
{ 
    public GlobalRegistry() 
    { 
     For<INotificationRepository>().Use<NotificationRepository>(); 
     ... 

,並在庫項目/類:

public class NotificationRepository : BaseRepository,INotificationRepository 
{ 
    public NotificationRepository(string userContext) : base(userContext) { } 

(由...魔術......)構造函數會在被調用的方法中使用userContext參數。

用SimpleInjector替換後,我不明白這個參數如何被注入。

出於測試目的,這個工程:

container.Register<INotificationRepository>(() => new NotificationRepository("username"), 
    Lifestyle.Singleton); 

我讀了我不應該在構造函數中注入HttpContext,因爲它是一個運行時的變量,我明白爲什麼。

接下來我嘗試了一個IUserContextFactory,但它也沒有工作。

同MVC項目,我有他的課:

public static class ObjectFactory 
{ 
    private static SimpleInjector.Container _container; 

    public static void SetContainer(Container container) 
    { 
     ObjectFactory._container = container; 
    } 

    public static T GetInstance<T>() where T : class 
    { 
     return _container.GetInstance<T>(); 
    } 
} 

我使用這個類來存儲容器後container.Verify();

ObjectFactory.SetContainer(container); 

在任何一個MVC控制器,我使用它像這樣:

IUserContext ctxUser = ObjectFactory.GetInstance<IUserContext>(); 

我也試過類似下面的資料庫中的東西,嘗試,但我總是以空UserName結束。

public NotificationRepository(IUserContext userContext) : base(userContext) { } 

public interface IUserContext 
{ 
    string Username { get; set; } 
} 

比知道該解決方案更重要的是(MVC項目和庫項目之間共用接口),我想了解解決方案的工作,克服我一直有難度在過去的幾個小時試圖理解和解決這個問題。

+0

那麼,還應該在'StructureMap'中對上下文進行註冊,並將其轉換爲其他語法。順便說一句,這個'Lifestyle.Singleton'看起來不太好。 –

+0

我不明白你的實際問題是什麼,你卡在哪裏以及你想了解什麼。 – Steven

+0

@Gert Arnold,沒有找到正在注入的StructureMap的上下文。 當用戶登錄時它保持不變,直到它註銷,我在哪裏丟失了什麼?多個用戶!? – chapas

回答

1

將運行時基元值作爲參數傳遞給構造函數不能直接在Simple Inject中使用。相反,您可以注入一個允許您在運行時獲取該值的組件,因此您使用IUserContext似乎是一種好方法,它應該可行。修改您的類以在構造函數中添加該組件,而不是userName字符串。註冊新組件,讓容器在調用構造函數時自動注入它。

的實現:

class HttpSessionUserContext : IUserContext 
{ 
    //Your specific implementation of getting the user name from your context 
    public string CurrentUserName => (string)HttpContext.Session["userName"]; 
} 

登記:

container.Register<IUserContext, HttpSessionUserContext>(Lifestyle.Scoped); 
container.Register<INotificationRepository, NotificationRepository> (Lifestyle.Scoped); 

Here您還有關於爲何通過原始的運行時參數的構造函數是不是在簡單的進樣實現的原因的詳細信息。

關於生活方式範圍:您可能不應該使用Lifestyle.Singleton作爲此組件的作用域,因爲它只會實例化一次並作爲單例重用。在Web應用程序中,您通常需要應用Per-HttpRequest範圍。你可以像下面這樣做:創建容器後,確定其默認範圍爲WebRequestLifestyle,或WebApiRequestLifestyle

var container = new Container(); 
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle(); 

然後當你註冊你的組件使用的值Lifestyle.Scoped,將應用默認範圍的生活方式:

container.Register<SomeInterface, SomeClass>(Lifestyle.Scoped); 

編輯:每Steven的評論,因爲在這種情況下,它會更好註冊HttpSessionUserContextSingleton,因爲它是無狀態的。通常,Singleton具有更好的性能,因爲它僅實例化一次並共享,但要注意那些非無狀態或對其他組件具有依賴性的組件。

此外,請確保您註冊了您的MVC控制器並將您的容器實例分配給您的MVC DependencyResolver。這是真正能夠自動解析和注入控制器中的構造函數中的參數。我想你在你的Application_Start事件處理程序中做了這個。

container.RegisterMvcControllers(Assembly.GetExecutingAssembly()); 
container.Verify(); 
DependencyResolver.SetResolver(
     new SimpleInjectorDependencyResolver(container)); 
+0

我同意你的答案戴安娜,謝謝你的幫助。 我在LoginControler注入IUserContext,然後在有效的用戶登錄後獲取用戶名,直到註銷纔會保持不變,但不會在這種情況下看到正確的東西。 – chapas

+0

由於'HttpSessionUserContext'類是無狀態的,它可以被註冊爲單例,因此我的建議是將它註冊爲單例。這樣做沒有任何壞處。事實上,我認爲最好有儘可能多的單身人士註冊。 – Steven

+0

@Steven你是對的,它會更好,更好的表現。如果性能不重要,我使用按照請求進行註冊的方式是保守的,但單例註冊更有效。只要注意那些非無狀態的組件或者對其他組件有依賴關係。 – Diana