2

I see a lot of questions and answers on this topic, however the vast majority are dealing with ASP.Net or other web based applications and something called .InRequestScope. I have yet to find this method in Ninject with a Windows Application.

I have the usual Unit of Work (UoW) and Repository (Repo) classes and Interfaces, but I am wanting to inject the same DbContext into both, each time a UoW is run from the DIContainer. My code looks like this;

public class UnitOfWork : IUnitOfWork, IDisposable
{
    private readonly FinancialContext _context;

    private IAccountRepository _accountRepository;
    public IAccountRepository Accounts
    {
        get { return _accountRepository; }
    }

    UnitOfWork(IMyContext context, IAccountRepository accountRepository)
    {
        _context = context;
        _accountRepository = accountRepository;
    }

    public void SaveChanges()
    {
        _context.SaveChanges();
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}

public class AccountRepository : Repository<Account>, IAccountRepository
{
    public AccountRepository(IMyContext context) : base(context) { }
}

The DIContainer holds the following associations;

Bind<IUnitOfWork>().To<UnitOfWork>().InTransientScope();
Bind<IUnitOfWorkFactory>().ToFactory();

Bind<IMyContext>().To<MyContext>().InSingletonScope();

Bind<IAccountTypeRepository>().To<AccountTypeRepository>().InTransientScope();

I'll come back to the .InSingletonScope();

The way I have seen people do this normally has been in the UoW Properties for each Repo to have code to this effect;

private IAccountRepository _accountRepository;
public IAccountRepository Accounts
{
    get 
    { 
         if(_accountRepository = null)
         {
             _accountRepository = new AccountRepository(_context);
         }
         return _accountRepository; 
    }
}

And remove the injected repositories from the Constructor, there by ensuring that each instance of a repository using the same _context.

However in my mind this breaks the Dependency Injection for this class. Is there a way to do this where each creation of a UoW like so;

public TestUnitOfWork(IUnitOfWorkFactory unitOfWork)
{
    using (var UoW = unitOfWork.Create())
    {
         Work done on UoW... 
    }
}

Currently the .InSingletonScope allows this, but is this keeping an instance of the context always open? Introducing the errors associated with not disposing a context properly?

Or is it better to create a Factory for the Repositories and give them a context parameter, then in the properties initialise it like so;

private IAccountRepository _accountRepository;
public IAccountRepository Accounts
{
    get 
    { 
         if(_accountRepository = null)
         {
             _accountRepository = RepositoryFactory.CreateAccountRepository(_context);
         }
         return _accountRepository; 
    }
}

Thanks in advance for any help!

Tristan Trainer
  • 2,770
  • 2
  • 17
  • 33
  • This one can be helpful for you:https://stackoverflow.com/questions/23081707/ninject-in-what-scope-dbcontext-should-get-binded-when-requestscope-is-meaning/48137975#48137975 – Jan Muncinsky Jun 22 '18 at 10:39
  • I am just wrestling with the exact same dilemma. Have you come across a viable solution to this yet or have you taken the RepositoryFactory route? I'll keep searching... – Michael Kargl Jul 20 '18 at 17:11
  • Hi Michael, I went with the Factory approach in the end, Ninject's Extensions.Factory uses DI to resolve it's dependencies, so if you are using Factory.Create() for an object, it resolves that objects dependencies too, so I believe this is still very testable and clean! – Tristan Trainer Jul 25 '18 at 09:30

1 Answers1

0

The solution is the use Ninject's Extensions.Factory class and pass in an IAccountFactory.Create() to initialise a new object. This then uses the DI Container to resolve its dependencies and doesn't break the DI approach.

Tristan Trainer
  • 2,770
  • 2
  • 17
  • 33