4

I'm attempting to use EasyNetQ with Ninject to log messages.

I've managed to setup Ninject as the EasyNetQ DI (I think), but when a message comes to a handler without a parameterless constructor (e.g. I need a repository bound in there), it doesn't resolve. Or atleast I believe that's the issue as I get a pretty generic error on the console.

I tell EasyNetQ to use Ninject like so :

RabbitHutch.SetContainerFactory(() => new NinjectAdapter(container));

I think this is all I need to set it up. The Ninject Adapter is the one from EasyNetQ.

My handler looks like the following :

public class ProfileDeactivatedUpdateHandler : IConsume<ProfileDeactivatedUpdate>
{
    private readonly IProfileRepository _profileRepository;

    public ProfileDeactivatedUpdateHandler(IProfileRepository profileRepository)
    {
        _profileRepository = profileRepository;
    }

    public void Consume(ProfileDeactivatedUpdate message)
    { 
        //Do Stuff. 
    }
}

If I add a parameterless constructor, and instead setup Ninject to be available through the ServiceLocator (Ugh), then it works. The handler is called fine, and I can find my repository via the ServiceLocator, So I know that atleast Ninject knows about the repository.

The error that pops up when it tries to handle a message is.

System.AggregateException: One or more errors occurred. ---> System.Exception: E
xception of type 'System.Exception' was thrown.
   at EasyNetQ.ReflectionHelpers.DefaultFactories`1.Get()
   at EasyNetQ.ReflectionHelpers.CreateInstance[T]()
   at EasyNetQ.AutoSubscribe.DefaultAutoSubscriberMessageDispatcher.Dispatch[TMe
ssage,TConsumer](TMessage message)
   at EasyNetQ.RabbitBus.<>c__DisplayClass6`1.<Subscribe>b__5(T msg)
   --- End of inner exception stack trace ---
---> (Inner Exception #0) System.Exception: Exception of type 'System.Exception'
 was thrown.
   at EasyNetQ.ReflectionHelpers.DefaultFactories`1.Get()
   at EasyNetQ.ReflectionHelpers.CreateInstance[T]()
   at EasyNetQ.AutoSubscribe.DefaultAutoSubscriberMessageDispatcher.Dispatch[TMe
ssage,TConsumer](TMessage message)
   at EasyNetQ.RabbitBus.<>c__DisplayClass6`1.<Subscribe>b__5(T msg)<---
MindingData
  • 11,924
  • 6
  • 49
  • 68

1 Answers1

4

So I have resolved this. Apparently when EasyNetQ instantiates a handler, it doesn't use the specified DI framework to do it (Boo!). You have to specify a "MessageDispatcher" implementation separately. Awesome! Oh... But... There is only an implementation for Autofac, not for Ninject (Boo! x2).

So, my pull request is here for the code to implement the event dispatcher for Ninject is here : https://github.com/mikehadlow/EasyNetQ/pull/309

For now, you can copy and paste that class into your project. Then in your NinjectModule or wherever you are setting up your bindings, you can do the following :

//Bind Message Dispatcher to Ninject event message dispatcher
NinjectMessageDispatcher messageDispatcher = new NinjectMessageDispatcher(Kernel);
Bind<IAutoSubscriberMessageDispatcher>().ToConstant(messageDispatcher);

Then wherever you are setting up your subscribers you can do something like the following (Note that this is for auto subscribing using the IConsume interface of EasyNetQ.

var subscriber = new AutoSubscriber(_serviceBus, "ProfileServices");
subscriber.AutoSubscriberMessageDispatcher = _dispatcher;
subscriber.Subscribe(Assembly.GetExecutingAssembly());

The important part is setting the MessageDispatcher manually to an instance of the ninject dispatcher. How you want to achieve this is up to you.

I think in the future, EasyNetQ probably needs to do this automatically. Obviously if you set the factory to use Ninject, chances are your handler will want to be using Ninject too.

Oh! And you can modify the above code to use the DI of your choice. This needs to be done for ANY DI in use with EasyNetQ (I think), not just Ninject.

MindingData
  • 11,924
  • 6
  • 49
  • 68