Search code examples
rebus

SimpleInjectorContainerAdapter, registering Sagas


Does the SimpleInjectorContainerAdapter support Sagas that are registered through the SimpleInjector container, using the following code I always get the exception;

type RebusPlaypen.MyMessageA, RebusPlaypen could not be dispatched to any handl ers

The following code demonstrates the issue. Could this be that I am implementing the Saga registration incorrectly, or does the SimpleInjectorContainerAdapter not support this type of registration ?

using Rebus.Bus;
using Rebus.Config;
using Rebus.Handlers;
using Rebus.Retry.Simple;
using Rebus.Routing.TypeBased;
using Rebus.Sagas;
using Rebus.SimpleInjector;
using Rebus.Transport.InMem;
using SimpleInjector;
using System;
using System.Threading.Tasks;

// Rebus.3.1.2
// Rebus.SimpleInjector.3.0.0

namespace RebusPlaypen
{
     public interface IMyDependency
     {
          void DoSomethingGood();
     }

     public class MyDependency : IMyDependency
     {
          public void DoSomethingGood()
          {
                Console.WriteLine("I've done something");
          }
     }

     public class MyMessageA
     {
          public Guid CollationId { get; set; }
          public string FaveIceCreamFlavour { get; set; }
     }

     public class MyMessageB
     {
          public Guid CollationId { get; set; }
          public string FaveBand{ get; set; }
     }

     public class MyMessageSagaData : ISagaData
     {
          public Guid Id {get;set;}
          public int Revision {get;set;}
          public Guid CollationId {get;set;}
          public bool HasFaveBand { get; set; }
     }

     public interface IMyMessageSaga : IAmInitiatedBy<MyMessageA>,
          IHandleMessages<MyMessageB>
     {
     }

     public class MyMessageSaga: Saga<MyMessageSagaData>,
          IMyMessageSaga
     {
          readonly IMyDependency _myDependency;
          readonly IBus _bus;

          public MyMessageSaga(IMyDependency myDependency,
                IBus bus)
          {
                _myDependency = myDependency;
                _bus = bus;
          }

          protected override void CorrelateMessages(ICorrelationConfig<MyMessageSagaData> config)
          {
                config.Correlate<MyMessageA>(s => s.CollationId, d => d.CollationId);
                config.Correlate<MyMessageB>(s => s.CollationId, d => d.CollationId);
          }

          public async Task Handle(MyMessageA message)
          {
                Console.WriteLine("Handled MyMessageA");
                _myDependency.DoSomethingGood();
                await _bus.Send(new MyMessageB { CollationId = message.CollationId, FaveBand = "Depeche Mode" });
                await PossiblyPerformCompleteAction();
          }

          public async Task Handle(MyMessageB message)
          {
                Console.WriteLine("Handled MyMessageB");
                _myDependency.DoSomethingGood();
                Data.HasFaveBand = true;
                await PossiblyPerformCompleteAction();
          }

          async Task PossiblyPerformCompleteAction()
          {
                if (Data.HasFaveBand)
                {
                     MarkAsComplete();
                }
          }
     }

     public static class RebusSimpleInjectorSagaDemo
     {
          public static void Run()
          {
                var container = new Container();
                container.Register<IMyDependency, MyDependency>();
                container.Register<MyMessageSaga>(Lifestyle.Transient);
                container.Register<IMyMessageSaga>(() => container.GetInstance<MyMessageSaga>(), Lifestyle.Transient);

                var network = new InMemNetwork(true);
                var adapter = new SimpleInjectorContainerAdapter(container);

                var _bus = Configure
                     .With(adapter)
                     .Logging(l => l.ColoredConsole(Rebus.Logging.LogLevel.Error))
                     .Transport(t => t.UseInMemoryTransport(network,"my_nice_queue"))
                     .Routing(r => r.TypeBased().MapAssemblyOf<MyMessageA>("my_nice_queue"))
                     .Options(o =>
                     {
                          o.SetNumberOfWorkers(1);
                          o.SetMaxParallelism(1);
                          o.SimpleRetryStrategy(maxDeliveryAttempts: 1);
                     })

                     .Start();

                container.Verify();

                _bus.Send(new MyMessageA { CollationId = Guid.NewGuid(), FaveIceCreamFlavour = "Strawberry" }).Wait();

                Console.WriteLine("Running");
                Console.ReadLine();
          }
     }
}

Solution

  • No matter which IoC container you use, you must ensure that your handlers are resolved by the IHandleMessages<TMessage> implementations they provide.

    If you try and

     container.GetAllInstances<IHandleMessages<MyMessageA>>();
    

    or

     container.GetAllInstances<IHandleMessages<MyMessageB>>();
    

    you will see that no handlers are returned. That's why Rebus cannot find any handlers to dispatch your messages to :)