Как использовать фабрику для создания интерфейса - PullRequest
1 голос
/ 13 октября 2019

У меня есть фабрика для создания общего сервиса:

public static class AdPersisterFactory<TEntity>
    where TEntity : AdBase
{
    public static AdPersister<TEntity> Create(ApplicationDbContext dbContext)
    {
        AdRepository<TEntity> adRepository = new AdRepository<TEntity>(dbContext);
        IAdImagePersister s3AdImagePersister = new S3AdImagePersister();
        AdPersister<TEntity> adPersister = new AdPersister<TEntity>(adRepository, s3AdImagePersister);
        return adPersister;
    }
}

Я хочу использовать ninject (версия 3), как я могу связать IAdPersister с экземпляром, который создает вышеуказанная фабрика ... Это мой код DI:

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<ApplicationDbContext>().ToSelf().InRequestScope();

    // I have tried the following which does not compile
    // kernel.Bind(typeof(IAdPersister<>)).ToMethod(ctx => AdPersisterFactory<>.Create(new ApplicationDbContext())); 
 }

Это для приложения ASp.NET MVC, поэтому в идеале я не хочу использовать новый ApplicationDbContext, но использовать тот же ApplicationDbContext, который существует в RequestScope.

Я также видел Ninject.Extensions.Factory , но я не уверен, как / если я могу использовать его в этом сценарии.

1 Ответ

1 голос
/ 14 октября 2019

Если вы готовы к рефакторингу для более твердого подхода, а AdRepository<TEntity> имеет интерфейс поддержки, такой как

public class AdRepository<TEntity> : IAdRepository<TEntity>
    where TEntity : AdBase {

    public AdRepository(ApplicationDbContext dbContext) {
        //...
    }
}

И при условии ...

public class AdPersister<TEntity> : IAdPersister<TEntity>
    where TEntity : AdBase {

    public AdPersister(IAdRepository<TEntity> adRepository, IAdImagePersister imagePersister) {
        //...
    }

    //...
}

Тогда способсоздание вашей открытой универсальной зависимости выглядело бы как

private static void RegisterServices(IKernel kernel) {
    kernel.Bind<ApplicationDbContext>().ToSelf().InRequestScope();
    kernel.Bind<IAdImagePersister>().To<S3AdImagePersister>();
    //Open generic bind for repository and ad persister
    kernel.Bind(typeof(IAdRepository<>)).To(typeof(AdRepository<>));
    kernel.Bind(typeof(IAdPersister<>)).To(typeof(AdPersister<>));
}

Теперь, когда требуется постоянная переменная, вы просто внедряете закрытый тип как

ctor(IAdPersister<Foo> fooPersister)

И необходимые зависимости будут разрешены и введеныконтейнер.

Эта статическая фабрика действительно не нужна.

ОБНОВЛЕНИЕ

На основании комментариев я все же советую не иметь статическую фабрику.

Если вы хотите сохранить подробности реализации внутри вашей библиотеки, сделайте фабрику экземпляром класса

public class AdPersisterFactory<TEntity> : IAdPersisterFactory<TEntity>
    where TEntity : AdBase {

    private readonly ApplicationDbContext dbContext;

    public AdPersisterFactory(ApplicationDbContext dbContext) {
        this.dbContext = dbContext;
    }

    public IAdPersister<TEntity> Create() {
        AdRepository<TEntity> adRepository = new AdRepository<TEntity>(dbContext);
        IAdImagePersister s3AdImagePersister = new S3AdImagePersister();
        AdPersister<TEntity> adPersister = new AdPersister<TEntity>(adRepository, s3AdImagePersister);
        return adPersister;
    }
}

, который может быть зарегистрирован как открытый универсальный объект в корне вашей композиции.

private static void RegisterServices(IKernel kernel) {
    kernel.Bind<ApplicationDbContext>().ToSelf().InRequestScope();        
    kernel.Bind(typeof(IAdPersisterFactory<>)).To(typeof(AdPersisterFactory<>));

}

и б

ctor(IAdPersisterFactory<Foo> fooPersisterFactory) {
    IAdPersister<Foo> fooPersister = fooPersisterFactory.Create();

    //...
}
...