2011-11-01 110 views
0

我使用Ninject,但是這應該適用於任何IoC。 我有一個後臺線程運行的單例,線程運行整個程序的生命週期。每5分鐘後臺線程開始幾個工作人員。這些工人使用的是autofac需要處理依賴關係的單例解決方案

Func<IEnumerable<IWorker>> 

注入但這只是利用了一些照顧的問題,讓我解釋一下,我的一些工人必須依賴於存儲庫和每個倉庫都依賴於它有一個實體框架上下文線程範圍(線程結束時將被處理)。這意味着當autofac被執行時,我得到一個工作者列表,他們的作用域將在與程序具有相同生命週期的後臺線程上,並不適合擁有整個應用程序的EF上下文。每個工作人員的Execute方法都是在一個單獨的線程中執行的,但這樣做並不重要,因爲Ninject仍然只會監聽永遠不會結束的主後臺線程。

,如果你問我,我有一個非常醜陋的方式解決了這個,現在我注入一個沒有通用的工廠

Func<Type, object> 

我然後問大會返回IWorker接口和我的所有具體類型,然後使用工廠方法在每個工作線程中調用它們(這意味着範圍將只用於工作線程而不是背景thead),這是有效的,但它很醜,我不能存根IWorkers,這意味着我不能運行我的單元測試任何更多。

你們對我有一個很好的解決方案嗎? :d感謝

編輯:感謝您的幫助雷莫,指定範圍的部分現在的作品,但原來的問題依然存在。這是我的測試代碼

使用WorkManager

internal class WorkflowManager : IWorkflowManager 
{ 
    private readonly Func<IWorker> testWorker; 
    private BackgroundWorker backgroundWorker; 

    public WorkflowManager(Func<IWorker> testWorker) 
    { 
     this.testWorker = testWorker; 
    } 

    public void Start() 
    { 
     backgroundWorker = new BackgroundWorker(); 
     backgroundWorker.DoWork += DoBackgroundWork; 
     backgroundWorker.RunWorkerAsync(); 
    } 

    public void Stop() 
    { 

    } 

    private void DoBackgroundWork(object sender, DoWorkEventArgs e) 
    { 
     var test = testWorker(); 
    } 

} 

它結合

kernel.Bind<IWorkflowManager>().To<WorkflowManager>().InSingletonScope(); 

工人

internal class TestWorker : IWorker, IDisposable 
{ 
    public TestWorker() 
    { 
     System.Diagnostics.Debug.WriteLine("Contructed!"); 
    } 

    ~TestWorker() 
    { 
     System.Diagnostics.Debug.WriteLine("Deconstructed!"); 
    } 

    public void Dispose() 
    { 
     System.Diagnostics.Debug.WriteLine("Disposed!"); 
    } 

} 

綁定

kernel.Bind<IWorker>().To<TestWorker>().InCallScope(); 

只有構造函數被調用...:/

回答

3

使用https://github.com/ninject/ninject.extensions.namedscope/wiki/InCallScope。使用此作用域將在工作人員從緩存收集或釋放垃圾時處置依賴關係。

像這樣設置應用程序。下一個版本不再需要此解決方法。

public static class NinjectMVC3 
{ 
    private static readonly Bootstrapper bootstrapper = new Bootstrapper(); 

    /// <summary> 
    /// Starts the application 
    /// </summary> 
    public static void Start() 
    { 
     DynamicModuleUtility.RegisterModule(typeof(OnePerRequestModule)); 
     DynamicModuleUtility.RegisterModule(typeof(HttpApplicationInitializationModule)); 
     bootstrapper.Initialize(CreateKernel); 
     bootstrapper.Kernel.Rebind<IResolutionRoot>().To<ContextPreservingResolutionRoot>(); 
    } 

    /// <summary> 
    /// Stops the application. 
    /// </summary> 
    public static void Stop() 
    { 
     bootstrapper.ShutDown(); 
    } 

    /// <summary> 
    /// Creates the kernel that will manage your application. 
    /// </summary> 
    /// <returns>The created kernel.</returns> 
    private static IKernel CreateKernel() 
    { 
     var kernel = new StandardKernel(); 
     RegisterServices(kernel); 
     return kernel; 
    } 

    /// <summary> 
    /// Load your modules or register your services here! 
    /// </summary> 
    /// <param name="kernel">The kernel.</param> 
    private static void RegisterServices(IKernel kernel) 
    { 
     kernel.Unbind<IResolutionRoot>(); 
    }   
} 
+0

感謝您輸入雷莫,我有ninject的nuget版本2.2,它沒有那個範圍? – Anders

+0

如果我從具有InCallScope的nuget下載了命名範圍擴展,它會崩潰並且說IResolutionRoot定義了兩次,看起來像這兩個lib都試圖註冊它?非常容易混淆這個..:D – Anders

+0

你使用哪些擴展?或者你自己註冊IResolutionRoot? –