Search code examples
c#wcfnhibernatecastle-windsorrebus

Rebus message handling in WCF context with NHibernate & Castle WCF Facility


We host some WCF service and we use Castle Windsor as IOC and use the WCF Facility to host the service:

Component.For<IInter1>()
    .ImplementedBy<Class1>()
    .LifestylePerWcfOperation()
    .AsWcfService()

All other dependencies are registered with the LifestylePerWcfOperation in Windsor.

Rebus handlers are like this:

public class TestCastleRebusHandler : IHandleMessages<CastleRebusMessage>
{
    public TestCastleRebusHandler(DependenchyWithWCFContext failsHere) { }
    public void Handle(CastleRebusMessage message) { }
}

Problems are all the registrations are PerWcfOperation and they cannot be injected into Rebus because the context is not WCF, when receiving the message. Rebus config is:

_adapter = new Rebus.Castle.Windsor.WindsorContainerAdapter(Container);
_bus = Configure.With(_adapter)
    .Logging(x => x.ColoredConsole(LogLevel.Info))
    .Transport(x => x.UseMsmqAndGetInputQueueNameFromAppConfig())
    .MessageOwnership(m => m.FromRebusConfigurationSection())
    .Subscriptions(x => x.StoreInMemory())
    .CreateBus()
    .Start();

What's the best approach for handling this scenario?

Ken


Solution

  • The best approach is to have a WindsorContainer instance per "logical application" in your process, where your logical applications would be one WCF application and one Rebus application.

    In general, it's just hard work and generally too uphill to be fun to try to configure lifestyles for your components to work in two different applications, which is actually what you're trying to do when you have one single container work for both WCF and Rebus.

    When you think about it, everything around lifestyle in an IoC container is configured to match one specific activation model, which in WCF context will often tie instances to WCF operations, as you do.

    In Rebus context, the transient lifestyle is generally preferable when possible, and everything will work as it should this way.

    Therefore, I suggest you host two containers in your process and configure each container to work completely independent of the other. This brings with it also a great flexibility because it will become trivial to separate the backend processing from the parts serving web requests further down the line.

    If you need to have an IBus in your WCF application, you can just configure a one-way client(*) for the WCF container.

    I hope that makes sense :)


    (*) please note that the docs have been updated to reflect the APIs of Rebus 2 (versions 0.90.0 and up) but they're very similar for old Rebus