Dependency Injection in Unit of Work Pattern Using Repositories

Dependency injection in unit of work pattern using repositories

A way to approach this is to not make the UnitOfWork responsible for creating each Repository through Container injection, but instead to make it the responsibility of each Repository to ensure that the UnitOfWork knows of its existence upon instantiation.

This will ensure that

  • your UnitOfWork doesn't need to change for each new Repository
  • you are not using a service locator (considered by many to be an anti-pattern)

This is best demonstrated with some code - I use SimpleInjector so the examples are based around this:

Starting with the Repository abstraction:

public interface IRepository 
{
void Submit();
}
public interface IRepository<T> :IRepository where T : class { }
public abstract class GenericRepository<T> : IRepository<T> where T : class { }

and the UnitOfWork

public interface IUnitOfWork
{
void Register(IRepository repository);
void Commit();
}

Each Repository must register itself with the UnitOfWork and this can be done by changing the abstract parent class GenericRepository to ensure it is done:

public abstract class GenericRepository<T> : IRepository<T> where T : class
{
public GenericRepository(IUnitOfWork unitOfWork)
{
unitOfWork.Register(this);
}
}

Each real Repository inherits from the GenericRepository:

public class Department { }
public class Student { }

public class DepartmentRepository : GenericRepository<Department>
{
public DepartmentRepository(IUnitOfWork unitOfWork): base(unitOfWork) { }
}

public class StudentRepository : GenericRepository<Student>
{
public StudentRepository(IUnitOfWork unitOfWork) : base(unitOfWork) { }
}

Add in the physical implementation of UnitOfWork and you're all set:

public class UnitOfWork : IUnitOfWork
{
private readonly Dictionary<string, IRepository> _repositories;
public UnitOfWork()
{
_repositories = new Dictionary<string, IRepository>();
}

public void Register(IRepository repository)
{
_repositories.Add(repository.GetType().Name, repository);
}

public void Commit()
{
_repositories.ToList().ForEach(x => x.Value.Submit());
}
}

The container registration can be set up to automatically pick up all the defined instances of IRepository and register them with a lifetime scope to ensure they all survive for the lifetime of your transaction:

public static class BootStrapper
{
public static void Configure(Container container)
{
var lifetimeScope = new LifetimeScopeLifestyle();

container.Register<IUnitOfWork, UnitOfWork>(lifetimeScope);

container.RegisterManyForOpenGeneric(
typeof(IRepository<>),
lifetimeScope,
typeof(IRepository<>).Assembly);
}
}

With these abstractions and an architecture built around DI you have a UnitOfWork that knows of all Repository's that have been instantiated within any service call and you have compile time validation that all of your repositories have been defined. Your code is open for extension but closed for modification.

To test all this - add these classes

public class SomeActivity
{
public SomeActivity(IRepository<Department> departments) { }
}

public class MainActivity
{
private readonly IUnitOfWork _unitOfWork;
public MainActivity(IUnitOfWork unitOfWork, SomeActivity activity)
{
_unitOfWork = unitOfWork;
}

public void test()
{
_unitOfWork.Commit();
}
}

Add these lines to BootStrapper.Configure()

//register the test classes
container.Register<SomeActivity>();
container.Register<MainActivity>();

Put a break-point against the line of code:

_repositories.ToList().ForEach(x => x.Value.Submit());

And finally, run this Console test code:

class Program
{
static void Main(string[] args)
{
Container container = new Container();
BootStrapper.Configure(container);
container.Verify();
using (container.BeginLifetimeScope())
{
MainActivity entryPoint = container.GetInstance<MainActivity>();
entryPoint.test();
}
}
}

You'll find the code stops at the break point and you have one active instance of a IRepository ready and waiting to Submit() any changes to the database.

You can decorate your UnitOfWork to handle transactions etc. I will defer to the mighty .NetJunkie at this point and recommend you read these two articles here and here.

Unit of Work and Repository Pattern in MVC controller constructor injection using Unity not doing any changes to database

It looks like your issue is the scope of your DbContext. Your UnitOfWork and GenericRepository<T> classes are getting different instances.

Not super familiar with Unity, but it looks like you want to use something like this for your DbContext registration:

container.RegisterType<DbContext, DashboadContext>(new PerRequestLifetimeManager());

This will create a single DashboardContext for each request, and your UnitOfWork and GenericRepository<T> classes will be working within the same context.

How to implement unit of work pattern with IServiceProvider injected in repositories?

As the error shows, you should not inject scoped lifetime dependencies into singletons. DbContexts are usually registered as scoped.

If the repositories depend on the context then they should be scoped as well.

For example.

services.AddScope<IUnitOfWork, UnitOfWork>(); 
services.AddScope<IRepositoryA, RepositoryA>();
services.AddScope<IRepositoryB, RepositoryB>();
services.AddDbContext<ApiContext>(options => options.UseInMemoryDatabase("Database"));

How to lazy inject repositories in unit of work pattern using dependency injection in asp.net core

Try to use IServiceProvider for such task.

public class UnitOfWork : IUnitOfWork
{
private readonly BaseContext _context;
private readonly IServiceProvider _provider;
private IAsyncRepository<CategoryEntity> _categoryRepository;
private IAsyncRepository<ItemEntity> _itemRepository;

public UnitOfWork(BaseContext context, IServiceProvider provider)
{
_context = context;
_provider = provider;
}

private T InitService<T>(ref T member)
{
return member ??= _provider.GetService<T>();
}

public IAsyncRepository<CategoryEntity> CategoryRepository
{
get
{
return InitService(ref _categoryRepository);
}
}

public IAsyncRepository<ItemEntity> ItemRepository
{
get
{
return InitService(ref _itemRepository);
}
}
}

.Net Dependency injection in unit of work pattern using repositories

The question you link to was a solution to ensure that the Unit Of Work was always aware of Repositories; the repository implementation itself was pretty useless! A Repository should, as a minimum, expose methods for all crud operations:

public interface IRepository<TEntity, in TKey> where TEntity : class
{
TEntity Read(TKey id);
TEntity Add(TEntity entity);
TEntity Update(TEntity entity);
void Delete(TKey id);
}

See this article for example.

How do I use Dependency Injection with Unit of Work and Repositories in C#? (Not a web based App)

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.



Related Topics



Leave a reply



Submit