Problem:

in my domain layer assembly I store two interfaces:

public interface IDomainEvent { }

and

public interface IHandle<T> where T: IDomainEvent, new()

EventDispatcher class is defined there also:

public static class EventDispatcher {
    [ThreadStatic]
    private static List<Delegate> actions;
    [ThreadStatic]
    private static List<Object> handlers;

    public static List<Object> Handlers { 
        get { return handlers; } 
        set { handlers = value; } 
    }

    public static void Register<T>(Action<T> callback) where T : IDomainEvent, new() {
        if(null == actions) {
            actions = new List<Delegate>();
            actions.Add(callback);
        }
    }

    public static void ClearCallbacks() {
        actions = null;
    }

    public static void Raise<T>(T @event) where T : IDomainEvent, new() {
        if(null != Handlers) {
            foreach(var handler in Handlers.Where(h => h is IHandle<T>)) {
                ((IHandle<T>)handler).Handle(@event);
            }
        }

        if(null != actions) {
            foreach(var action in actions) {
                if(action is Action<T>) {
                    ((Action<T>)action)(@event);
                }
            }
        } // if(null != actions) {
    }
}

There's a module in presentation layer assembly:

public class EventDispatchingModule : NinjectModule {

    public override void Load() {

        // EventDispatcher.Handlers = this.Kernel.GetAll(IHandle<T>); Can't do that!
        // Bind<IHandle<CarHasBeenRegisteredEvent>>().To<CarHasBeenRegisteredHandler();
    }
}

So I can't call Kernel.GetAll(IHandle<T>) there because it can't resolve T parameter.

Howcome I resolve this?

Thanks!

有帮助吗?

解决方案

No need to use a module (I've not used ninject, but something similar):

// Put these in the domain project

public class EventDispatcher
{
    private static IEventDispatcher _dispatcher;

    public static void Setup(IEventDispatcher dispatcher)
    {
        _dispatcher = dispatcher;
    }

    public static void Dispatch<T>(T domainEvent) where T : IDomainEvent
    {
        _dispatcher.Dispatch<T>(domainEvent);
    }
}

public interface IEventDispatcher
{
    public void Dispatch<T>(T domainEvent) where T : IDomainEvent;
}


// and this one in the project which has Ninject

public class NinjectEventDispatcher : IEventDispatcher
{
    private static IKernel _container;

    public NinjectEventDispatcher(IKernel container)
    {
        _container = container;
    }

    public void Dispatch<T>(T domainEvent) where T : IDomainEvent
    {
        foreach (var listener in _container.GetAll<IHandle<T>>())
        {
            listener.Handle(domainEvent);
        }
    }
}

// And after the container have been configured:
EventDispatcher.Setup(new NinjectEventDispatcher(_container));

But I don't know how ninject handles scoped objects (which may also want to receive the events).

My container has domain events built in, read more in this article: http://www.codeproject.com/Articles/440665/Having-fun-with-Griffin-Container

Update:

I've updated the code sample to make the domain project unaware of Ninject.

You are not using Service Location with this code. The internals of the event dispatcher is. i.e. none of your code is affected by it.

其他提示

You can get all Handlers with following code

Kernel.GetAll(typeof (IHandle<>));

But anyway it's not good idea to load all IHanders in NInjectModule because you don't know if another modules are already loaded or not (and another modules can register Handlers too). I suggest make EventDispatcher class not static and register it in scope that you need (If you need new handlers for each request - in request scope, otherwise - in singleton scope . Handlers you can inject with constructor like :

Kerner.Bind<EventDispatcher>().ToSelf()
      .InRequestScope()
      .WithConstructorArgument("handlers", c => c.Kernel.GetAll(typeof(IHandler<>)))

Hope this helps

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top