具有依赖性的单例的解决方案需要处理

时间:2011-11-01 09:12:48

标签: singleton inversion-of-control ninject

我使用Ninject但这适用于任何IoC。 我有一个运行后台线程的单例,该线程运行整个程序的生命周期。每5分钟后台线程启动一些工作人员。这些工人使用autofac进行注射

Func<IEnumerable<IWorker>>

但这只涉及一些问题,让我解释一下,我的一些工作者依赖于存储库,每个存储库都依赖于具有线程范围的Entity框架上下文(它将在线程结束时处理)。这意味着当执行autofac并获得一个工作列表时,它们的范围将位于与程序具有相同生命周期的后台线程上,不适合拥有适用于整个应用程序的EF上下文。每个worker Execute方法都是在一个单独的线程中执行的,但是这样做就没有关系,因为Ninject仍然只会监听永远不会结束的主后台线程。

如果你问我,我现在以一种非常丑陋的方式解决了这个问题,我注入了一个非通用的工厂

Func<Type, object> 

然后我要求程序集返回IWorker接口的所有具体类型,然后我使用工厂方法在每个工作线程中调用它们(这意味着范围将仅用于工作线程而不是背景thead),这是有效的,但它很难看,我不能把IWorkers存在,这意味着我不能再运行我的单元测试了。

你们有一个很好的解决方案吗? :D谢谢

编辑:感谢Remo的帮助,命名范围部分现在可以正常工作,但原始问题仍然存在..这是我的测试代码

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();

只有构造函数被调用...:/

1 个答案:

答案 0 :(得分: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>();
    }        
}