Reputation: 51
I'm trying to create an application with DDD, implementing Domain Events, using Entity Framework and StructureMap for dependency injection.
I created an abstraction of UnitOfWork and Repositories. Obviously, the IUnitOfWork implementation encapsulates the DbContext, and all instances are injected by StructureMap (Nested Container's per HTTP request), so the IUnitOfWork injected in all repositories (Also injected) are the same instance (By the way, for the same reason, only one instance of DbContext is created per request).
UnitOfWork implementation is like this...
public class EFUnitOfWork : IUnitOfWork, IDisposable
{
public EFUnitOfWork(ApplicationDbContext dbContext)
{
Context = dbContext;
}
...
... and repositories are like..
public class BaseRepository<T, TId> : IRepository<T, TId>, IAggregateRoot
{
private readonly IUnitOfWork _unitOfWork;
// All the repositories created are automaticaly injected
// with the same IUnitOfWork instance during the request.
public BaseRepository(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
...
All this works well, and I can manage my changes in the context using my IUnitOfWork instance.
public class UsersService : IUsersService
{
private readonly IUnitOfWork _unitOfWork;
private readonly IUserRepository _userRepository;
public UsersService(IUnitOfWork unitOfWork, IUserRepository userRepository)
{
_unitOfWork = unitOfWork;
_userRepository = userRepository;
}
public override CreateUserUseCaseResult HandleExecute(CreateUserUseCaseRequest input)
{
var user = Mapper.Map<User>(input.User);
_userRepository.Insert(user);
...
_unitOfWork.SaveChanges();
return new CreateUserUseCaseResult
{
User = Mapper.Map<UserViewModel>(user)
};
}
}
The Problem
I want to implement Domain Events, and the idea is to have an static class with the method to publish the events in this way:
DomainEvents.Publish(new TheDomainEvent() { Data = "something" });
So I can use it inside of domain objects like Entities.
But for it to work I need not only access to my container instance (where all event handlers are registered), I need access to the current nested container instance to share the same IUnitOfWork instance (I don't need the IUnitOfWork directly, but I need to have the same instance injected in all repositories) so any operation inside the event handlers can be performed on the same DbContext).
So... How can I have an static class with a publish method, to be available in the domain?
For now, I temporary worked around the problem injecting a IDomainBus instance on the services, so the current nested container is used to create the event handler instances.
public class SomeService : ISomeService
{
private readonly IDomainBus _domainBus;
public UsersService(IDomainBus domainBus, ...)
{
_domainBus= domainBus;
}
public void PerformSomeOperation(OperationRequest data)
{
...
_domainBus.Publish(new SomeOperationPerformed() { Data = data });
...
But I can't use this solution if I want to publish an event from inside a domain entity like this:
public class User : IEntity
{
public User() { }
public void UpdatePassword(string newPassword)
{
...
DomainEvents.Publish(new UserPasswordUpdatedEvent() { User = this });
...
}
A possible solution...
A possible solution is to store the DbContext in the HttpContextand retrieve it from there in the repositories. So that, the repositoriy instances and the IUnitOfWork instance will be different, but the DbContext used will be the same.
I dont like this solution because I dont want to use the HttpContext.
Maybe having some way to get the current request's nested container...
Can you show me some light? Thanks
Upvotes: 1
Views: 395
Reputation: 51
Looking at the StructureMap documentation I found this way.
Configure the UnitOfWork (The DbContext in fact) registry, setting the lifecycle to HttpContextLifecycle in the next way:
var container = new Container(_ =>
{
_.For(typeof (IUnitOfWork)).Use(typeof (EFUnitOfWork))
.SetLifecycleTo(new HttpContextLifecycle());
I'm not totally convinced about this solution, but is better than implement my own UnitOfWork/DbContext storage over the HttpContext.
Upvotes: 0