This project is read-only.

container.RegisterPerWcfOperation<IUnitOfWork, UnitOfWork>() with DomainEvents

May 3, 2014 at 11:51 PM
(moved from 'issues')

In a WCF service, IUnitofWork is injected into the Repositories (sharing the db connection and transaction - access to EF DbContext) - all is well.

However implementing DomainEvents (http://www.udidahan.com/2009/06/14/domain-events-salvation/) where upon raising a DomainEvent, the DomainEventHandler is injected with another domain service (that is injected with a Repository, that is injected with IUnitOfWork)

Domain service (Repository injected):
public class UserService : IUserService
    {
        private IRepository<User> _repoUser;
        private IRepository<Role> _repoRole;

        public UserService(IRepository<User> repoUser, IRepository<Role> repoRole)
        {
            _repoUser = repoUser;
            _repoRole = repoRole;
        }
Wcf service injected with DomainService and UoW:
public UserAppService(IUnitOfWork uow, IUserService service)
        {
            _uow = uow;
            _service = service;
        }
uow injected here to commit transactions at this AppService layer. uow is also injected into Repositories (giving access to the DbContext.DbSet) which are injected into the DomainService (IUserService). All this is working as expected.

In the DomainService, a domain event is raised:
 DomainEvents.Raise(new UserStartedRegistration() { User = user });
static DomainEvents.Raise gets the event and dispatches to all registered handlers. Maybe static here is a problem?
public static void Raise<T>(T args) where T : IDomainEvent
        {
            if (Container != null)
            {
                foreach (var handler in Container.GetAllInstances<IDomainEventHandler<T>>())
                    handler.Handle(args);
this works as expected, unless the handler expects a UnitOfWork in it's graph (by injecting another DomainService with Repositories). Here the UserService is injected, but it could be another DomainService (http://mikehadlow.blogspot.com/2010/09/separation-of-concerns-with-domain.html)
public UserNotificationHandler(IUserService service)
        {
            _service = service;
        }
In this case I am getting the error when a domain event (UserStartedRegistration) is raised:

The registered delegate for type IDomainEventHandler<UserStartedRegistration> threw an exception. The IUnitOfWork is registered as 'WCF Operation' lifestyle, but the instance is requested outside the context of a WCF Operation.

The error makes sense, but code is still executing the wcf service call. Is there a way to configure the container to inject the UnitOfWork when a DomainEventHandler requires a Domain Service (and subsequently dependent on Repository and UnitOfWork?
comments

Ideally the container would be able to instantiate a new UnitOfWork for the Domain Service being injected into the Domain Event Handler since any operations there are not part of the original uow transaction. Consider the example (the Domain Event Handler is injected with a Repository to handle the event):
http://mikehadlow.blogspot.com/2010/09/separation-of-concerns-with-domain.html

Maybe a new container method would support this scenario like:
container.RegisterPerWcfOperationPlusExternalContext
May 3, 2014 at 11:54 PM
wcf startup registrations:
assembly = System.Reflection.Assembly.Load("App.Core.EventHandlers");
            container.RegisterManyForOpenGeneric(typeof(IDomainEventHandler<>), (service, impls) => container.RegisterAll(service, impls), assembly);
            
            //inject the same uow to the service to start/stop the transaction, and the repository to manage data with the transacion
            container.RegisterPerWcfOperation<IUnitOfWork, UnitOfWork>();
May 4, 2014 at 9:48 AM
Edited May 4, 2014 at 11:36 AM
From the code you present, it's not clear to me why you are getting the "IUnitOfWork is registered as 'outside the context of a WCF Operation" exception. The Scope instance for the WcfOperationLifestyle is stored in a ThreadLocal<T> valuable as long as the WCF request runs. This means that any time you call container.GetInstance during that request, you are running inside that scope. So either you are spinning off operations in parallel -or- you are running your WCF service asynchronously.

But either way, you want to give each event handler its own new context, transaction. You would like to run them in isolation. There's nothing missing from the framework from doing this, but you need to set this up explicitly. What you need is to wrap your event handlers with a decorator that allows starting this new scope. For instance:
public class LifetimeScopeEventHandlerDecorator<T> : IEventHandler<T>
{
    private readonly IEventHandler<T> decorateeFactory;
    private readonly Container container;

    public LifetimeScopeEventHandlerDecorator(
        Func<IEventHandler<T>> decorateeFactory, Container container) {
        this.decorateeFactory = decorateeFactory;
        this.container = container;
    }

    public void Handle(T message) {
        using (container.BeginLifetimeScope()) {
            var decoratee = this.decorateeFactory.Invoke();
            decoratee.Handle(message);
        }
    }
}
This decorator starts a lifetime scope and resolves the decoratee INSIDE this scope and calls Handle on it. You can register this decorator as follows:
// using SimpleInjector.Extensions;
container.RegisterDecorator(typeof(IEventHandler<>), 
    typeof(LifetimeScopeEventHandlerDecorator<>));
Since this decorator expects the lifetime scope, you will how have to create a hybrid lifestyle that mixes the WCF lifestyle with the lifetime scope:
var hybridLifestyle = Lifestyle.CreateHybrid(
    container.GetCurrentLifetimeScope() != null,
    new LifetimeScopeLifestyle(),
    new WcfOperationLifestyle());
You should use this hybrid lifestyle to make your unit of work registrations in:
container.Register<IUnitOfWork, UnitOfWork>(hybridLifestyle);
On thing is still missing though, beceause since you run the event handlers in their own dbcontext etc, you will have to use a second decorator to commit the transaction:
public class TransactionalEventHandlerDecorator<T> : IEventHandler<T>
{
    private readonly IEventHandler<T> decoratee;
    private readonly IUnitOfWork unitOfWork;

    public TransactionalEventHandlerDecorator(IEventHandler<T> decoratee,
        IUnitOfWork unitOfWork) {
        this.decoratee= decoratee;
        this.unitOfWork= unitOfWork;
    }

    public void Handle(T message) {
        this.decoratee.Handle(message);
        this.unitOfWork.Commit();
    }
}
This decorator should get wrapped by the previous, so the registration should be as follows:
// using SimpleInjector.Extensions;
container.RegisterDecorator(typeof(IEventHandler<>), 
    typeof(TransactionalEventHandlerDecorator<>));
container.RegisterDecorator(typeof(IEventHandler<>), 
    typeof(LifetimeScopeEventHandlerDecorator<>));
May 4, 2014 at 11:42 AM
Edited Sep 28, 2014 at 12:21 PM
Here are some additional thoughts:
Marked as answer by dot_NET_Junkie on 9/28/2014 at 4:20 AM
May 4, 2014 at 5:40 PM
The wcf [OperationContract]s are all async, thanks for the quick and detailed response, and suggestions!