Управление временем жизни объектов, созданных фабрикой, сгенерированной ToFactory()

Я использую следующие пакеты nuget, связанные с Ninject, в приложении MVC 5 WebAPI:

Ninject.MVC5

Ninject.Extensions.Factory

ninject.extensions.conventions

У меня есть простой репозиторий и соответствующий фабричный класс:

public interface ITaskRunner
{
    void Run();
}
public interface IRepository<T> where T: class
{
    T[] GetAll();
}
public interface IRepositoryFactory<T> where T: class
{
    IRepository<T> CreateRepository();
}

Я настроил привязки Ninject с помощью ToFactory() из Ninject.Extensions.Factory следующим образом:

 kernel.Bind<ITaskRunner>().To<TaskRunner>().InSingletonScope();
 kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope();
 kernel.Bind<IRepositoryFactory<Contact>>().ToFactory();

Я использую фабрику в следующем классе:

public class TaskRunner : ITaskRunner
{        
    //MyTask is a simple POCO class(not shown for brevity)
    IRepositoryFactory<MyTask> repoFactory = null;
    IRepository<MyTask> repo = null;
    public TaskRunner(IRepositoryFactory<MyTask> repoFactory)
    {
        this.repoFactory = repoFactory;
        repo = repoFactory.CreateRepository();
    }
    //implementation elided
}

Я заметил, что вызов repoFactory.CreateRepository() всегда возвращает тот же экземпляр фабрики (динамический прокси), который генерирует Ninject.

Вопрос. Есть ли способ изменить/управлять этим поведением и установить время жизни, такое как Transient, PerThread и т. д., для экземпляра, возвращаемого CreateRepository? ?

В этом конкретном случае задачи могут обрабатываться асинхронно в нескольких потоках, а репозиторий не является потокобезопасным, и, следовательно, одноэлементное поведение для экземпляра, возвращаемого из CreateRepository, нежелательно.


person Abhijeet Patel    schedule 03.11.2015    source источник
comment
у вас установлено Ninject.Extensions.ContextPresevation?   -  person BatteryBackupUnit    schedule 03.11.2015
comment
Нет, у меня не установлено это   -  person Abhijeet Patel    schedule 03.11.2015


Ответы (1)


Я не уверен, чего вы пытаетесь достичь, но результаты, которые вы видите, вполне ожидаемы, потому что ваш TaskRunner связан как Singleton (поэтому создается один раз), и вы извлекаете свой репозиторий в конструкторе TaskRunner, что снова происходит один раз, и так репо всегда один и тот же экземпляр. Обратите внимание, что это происходит независимо от того, как вы связываете IRepository и IRepositoryFactory, подробности см. в статье Captive Dependency Марка Симанна http://blog.ploeh.dk/2014/06/02/captive-dependency/.

На самом деле, если вам нужно создать репо в конструкторе, вы можете просто внедрить сам IRepository. Сила расширения Factory заключается в том, что оно позволяет разрешать экземпляры во время выполнения, а не во время создания. Например, если в вашем TaskRunner есть метод Run(), вы можете создать в нем репозиторий, чтобы каждая запускаемая задача могла иметь свой собственный экземпляр.

person ovolko    schedule 13.11.2015
comment
Хороший момент. Я упростил пример. По правде говоря, я хотел бы сохранить синглтон для фабрики репо (в ctor), но разрешать разные репозитории в методе Run(), поскольку Run() будет многопоточным. Кажется, я заметил, что CreateRepository всегда будет возвращать один и тот же экземпляр репо. Затем я установил ContextPreservationExtension, который, кажется, обеспечивает желаемое поведение, т.е. CreateRepository теперь возвращает отдельные экземпляры репо при каждом вызове. - person Abhijeet Patel; 14.11.2015