Reputation: 2089
This should hopefully be easy to explain, but I'm not sure how to implement the solution into my DI container (Autofac).
I've got a Repository
public class ClientRepository
{
public ClientRepository(MyContext context)
{
}
}
And then a Unit-Of-Work
public class UnitOfWork
{
public UnitOfWork(MyContext context, ClientRepository repository)
{
}
}
The unit-of-work/repository pattern dictates that the DataContext that the Unit-Of-Work is instantiated with should be passed into the constructor of the Repository, that way everything is using the same DataContext
In other words, AutoFac should essentially should do this...
MyContext context = new MyContext();
ClientRepository clientRepository = new ClientRepository(context);
UnitOfWork unitOfWork = new UnitOfWork(context, clientRepository);
How can I tell Autofac to wire this up correctly?
In response to Cyril's comment about using Func>...
I have a class "ClientService" that needs one or more of these UnitOfWorks. In the example below, there should be no dependency sharing across the unit of works for "Add" and "Delete" (Unless I've registered a dependency as a Singleton). If I don't use Func>, e.g. separate scopes, how could I achieve this separation?
public class ClientService
{
private readonly Func<Owned<UnitOfWork>> _unitOfWorkFactory;
public ClientService(Func<Owned<UnitOfWork>> unitOfWorkFactory)
{
_unitOfWorkFactory = unitOfWorkFactory;
}
public AddClients(Clients c)
{
using(var uoc = _unitOfWorkFactory())
{
}
}
public DeleteClients(Clients C)
{
using(var uoc = _unitOfWorkFactory())
{
}
}
}
Upvotes: 0
Views: 202
Reputation: 29
To make Autofac essentially do what you want you need:
So
public static class DependencyContainer
{
internal static IContainer Container;
public static IContainer CreateContainer(Assembly assembly)
{
var builder = new ContainerBuilder();
builder.RegisterControllers(assembly);
IModule[] modules =
{
//You don't have to create lots of modules...
//but it would be better to have different modules for different application layers
new DataModule( /*some params if you need*/),
new DataAccessModule( ),
//new BusinessLogicModule(),
//...
};
foreach (var module in modules)
{
builder.RegisterModule(module);
}
return Container;
}
}
2-3. Implementing modules used in container and register types
DataModule:
internal class DataModule : Module
{
protected override void Load(ContainerBuilder builder)
{
//When you specify InstancePerRequest it means that everything (resolved via this DI)
//is using the same DataContext for current request
builder.RegisterType<MyContext>().As<MyContext>().InstancePerRequest();
}
}
DataAccessModule:
internal class DataAccessModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<UnitOfWork>().As<UnitOfWork>().InstancePerRequest();
builder.RegisterType<ClientRepository>().As<ClientRepository>().InstancePerRequest();
//if you are using generic repository you can register all them in one line like this:
//builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).InstancePerRequest();
}
}
Set DependencyResolver in Global.asax.cs
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
//Default Application_Start() content
//...
//Using our DI
var container = DependencyContainer.CreateContainer(typeof(MvcApplication).Assembly);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
Usage example
public class MyController : Controller
{
private readonly UnitOfWork _unitOfWork;
private readonly ClientRepository _clientRepository;
public MyController(UnitOfWork unitOfWork, ClientRepository clientRepository)
{
_unitOfWork = unitOfWork;
_clientRepository = clientRepository;
}
//When you are calling action DoSomething, you don't have to worry about constructor params (DI will pass them)
public ActionResult DoSomething()
{
_clientRepository.DoSomething();
return PartialView("DoSomething");
}
}
Upvotes: -1