Решение для синглтона с зависимостью, которую нужно утилизировать - PullRequest
0 голосов
/ 01 ноября 2011

Я использую Ninject, но это должно относиться к любому IoC. У меня есть синглтон с фоновым потоком, который работает в течение всего срока службы программы. Каждые 5 минут фоновый поток запускает пара рабочих. Эти рабочие вводятся с использованием автофака

Func<IEnumerable<IWorker>>

Но это решает только некоторые проблемы, позвольте мне объяснить, что некоторые из моих работников имеют зависимость от репозиториев, и каждый репозиторий имеет зависимость от контекста среды Entity, имеющей область видимости потока (Он будет удален после завершения потока ). Это означает, что когда выполняется автофак, и я получаю список работников, их область действия будет находиться в фоновом потоке, который имеет то же время жизни, что и программа, не очень хорошо иметь контекст EF, который живет для всего приложения. Каждый рабочий метод Execute выполняется в отдельном потоке, но это не имеет значения, поскольку Ninject все равно будет прослушивать только основной фоновый поток, который никогда не закончится.

Я решил это очень уродливо, если вы спросите меня, я ввожу не универсальную фабрику

Func<Type, object> 

Затем я прошу сборку вернуть все конкретные типы интерфейса IWorker, а затем использую фабричный метод для их вызова в каждом рабочем потоке (что означает, что область действия будет только для рабочего потока, а не для фонового потока), это работает, но это уродливо, и я не могу заглушить IWorkers, что означает, что я больше не могу запускать свои юнит-тесты.

Ребята, у вас есть хорошее решение для меня? : D Спасибо

edit: Спасибо за помощь, 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 Ответ

3 голосов
/ 01 ноября 2011

Использовать 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>();
    }        
}
...