Проблемы с Autofac-отношениями с MVC с использованием Unit of work и шаблона репозитория - PullRequest
0 голосов
/ 31 декабря 2018

В настоящее время я настраиваю новое веб-приложение MVC, используя внедрение зависимостей (autofac).Я действительно знал, что такое инъекция зависимостей, поэтому я чувствую, что мне чего-то не хватает.У меня есть рабочее решение (опубликовано ниже), но я чувствую, что мое решение идет вразрез с тем, что пытается сделать Autofac, путем разрешения зависимостей.

По сути, у меня есть служба, эта служба имеет несколько UnitOfWork, каждыйUnitOfWork имеет несколько репозиториев, и они совместно используют один экземпляр dbcontext (принадлежит UnitOfWork).Мне нужно, чтобы IDatabaseFactory создавался для передачи UnitOfWork в репозиторий.Это сделано для того, чтобы хранилище не могло утилизировать контекст, который используется другим хранилищем в экземпляре singleUnitOfWork.

Это то, что я пробовал.

Упрощенный макет службы

public class NewsletterService :INewsletterService
{
    TestUnitOfWork _uow1;
    TestUnitofWork2 _uow2;

    public NewsletterService(TestUnitOfWork uow, TestUnitOfWork2 uow2 )
    {
        _uow1 = uow;
        _uow2 = uow2;
    }
}

Простая реализованная единица работы (интерфейсы, основанные на примерах из msdn) Я оставил интерфейс вне, он просто делает вещи, которые не имеют отношения к проблеме (мы не можем пройти мимо конструкции).ContactSubscription - это просто модель.

public class TestUnitOfWork : UowBase, IUnitOfWork
{
    public TestUnitOfWork(IDatabaseFactory factory,
        GenericRepository<ContactSubscription> repo)
        : base(factory)
    {

    }
}

Общий репо

public class GenericRepository <TEntity> : IRepository<TEntity> where TEntity : class
{
    private readonly ApplicationDbContext _context;
    private readonly DbSet<TEntity> _dbSet;

    public GenericRepository(IDatabaseFactory factory)
    {
        _context = factory.Get();
        _dbSet = _context.Set<TEntity>();
    }

    public virtual IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null, 
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")
    {
        // ...
    } 
}

Реализация базы данных фабрики

public class UniqueDatabaseFactory : IDatabaseFactory
{
    private ApplicationDbContext _context;
    public Guid guid = Guid.NewGuid();  // using guid to quickly check instances.
    public ApplicationDbContext Get()
    {
        return _context ?? ( _context = ApplicationDbContext.Create());
    }
}

и регистрация выглядит следующим образом:

builder.RegisterType<NewsletterService>()
            .As<INewsletterService>()
            .InstancePerRequest();

builder.RegisterGeneric(typeof(GenericRepository<>))
            .AsSelf()
            .As(typeof(IRepository<>))
            .InstancePerLifetimeScope();
builder.RegisterType<TestUnitOfWork>().AsSelf().InstancePerRequest();
builder.RegisterType<TestUnitOfWork2>().AsSelf().InstancePerRequest();
builder.RegisterType<UniqueDatabaseFactory>().As<IDatabaseFactory>().InstancePerLifetimeScope();

Мои результаты до сих пор При использовании UnitOfWork в качестве InstancePerRequest мы получаем хорошие, но не очень хорошие результаты.IDatabaseContext используется всеми экземплярами UnitOfWork для службы-владельца.Кажется, что другие методы регистрации с autofac создают новый экземпляр IDatabaseFactory для каждого использования, например.использование InstancesPerLifetimeScope при регистрации.

Рабочее (но не правильное) решение

В качестве альтернативы этот метод сработал, но, будучи новичком в внедрении Dependency, кажется, что я иду противто, что пытается сделать Autofac, разрешая зависимости.

builder.Register(c =>
{
    IDatabaseFactory factory = c.Resolve<IDatabaseFactory>();
    GenericRepository<ContactSubscription> repo = c.Resolve<GenericRepository<ContactSubscription>>(
        new NamedParameter("factory", (object)factory));

    return new TestUnitOfWork(factory, repo);
}).AsSelf().InstancePerLifetimeScope();

Я сильно чувствую, что приведенное выше решение не является идеальным (с небольшими знаниями, которые у меня есть с контейнерами loc), и вместо того, чтобы причинять себе больше головной болиВ дальнейшем я хочу посмотреть, есть ли более эффективный способ иметь IDatabaseFactory, которая создается Autofac для UnitOfWork, чтобы передавать те же экземпляры в хранилище, но не сохранять тот же экземпляр для других UnitOfWork.

Мой проект сейчас беспорядок, так что, надеюсь, в коде примера нет опечаток или старых переменных, которые я пропустил.Спасибо!

1 Ответ

0 голосов
/ 31 декабря 2018

После небольшого перерыва я нашел решение своей проблемы.Поскольку UnitOfWork уже абстрагирует контекст базы данных, а UnitOfWork является внедряемой зависимостью, теперь каждый UnitOfWork контролирует создание и время жизни каждого репозитория.Было ненужно вводить репозитории.

Вот мое решение:

public interface INewsletterUnitOfWork
{
    IRepository<Newsletter> NewsLetters { get; }
    IRepository<ContactSubscription> ContactSubscriptions { get; }
}

public class NewsletterUnitOfWork : UowBase, INewsletterUnitOfWork
{
    private IRepository<Newsletter> _newsletters;
    public IRepository<Newsletter> NewsLetters
    {
        get { return _newsletters ?? (_newsletters = new GenericRepository<Newsletter>(Context)); }
        private set { _newsletters = value; }

    }
    private IRepository<ContactSubscription> _contactSubscriptions;
    public IRepository<ContactSubscription> ContactSubscriptions
    {
        get { return _contactSubscriptions ?? (_contactSubscriptions = new GenericRepository<ContactSubscription>(Context)); }
        private set { _contactSubscriptions = value; }

    }

    public NewsletterUnitOfWork(IDatabaseFactory factory)
        : base(factory)
    { }
}

и регистрация хорошая, простая и чистая.

        builder.RegisterType<DefaultDatabaseFactory>().As<IDatabaseFactory>().InstancePerLifetimeScope();

        builder.RegisterType<NewsletterUnitOfWork>()
            .AsSelf()
            .As<INewsletterUnitOfWork>()
            .InstancePerLifetimeScope();
...