Injecting the backoffice into the backoffice

Heads Up!

This article is several years old now, and much has happened since then, so please keep that in mind while reading it.

When I am spending time with the Umbraco 7 backoffice, it's so nice I would almost forget there are other backoffice applications too. Yes, those nasty dynosaurs which basically have my quality time for diner. All those hours I spent on data integration.... Why not do some cool stuff with dependency injection and inversion of control. And save some time... so you can spend more time with Belle. 

First for some theory. A formal definition of a backoffice could be:

area in a bank where checks are paid, deposits and withdrawals are posted to accounts, and interest earned on deposits is credited to the account holders

When I translate this to e-commerce it happens a customer purchases something at a webshop. Then the ERP system receives the data and processes a journal entry of the purchase. And the CRM systems gets an update with the e-mail address, the product SKU and other relevant data. So the marketing department can target their e-mails campaigns.

To implement this use case I would have the following data.

<order>
    <id>12345</id>
	<orderDate>2013-12-23</orderDate>
	<firstName>Merijn</firstName>
	<lastName>van Mourik</lastName>
	<email>mmourik(at)gmail(dot)com</email>
	<sku>1234</sku>
</order>

Houston we got an order!

After the order is finalized, I usually store it somewhere on a disk. Then at a certain point in time a batch job gets triggered and picks it up for further processing. 

Wouldn't it nice if I can just send it to CRM or ERP without having to worry about making connections to other servers. Or scheduling all kind of batch jobs. What if I could have just one single command to get the data to its destination.

RegisterOrder order = new RegisterOrder();

order.id = "12345";
order.orderDate = "2013-12-23";
order.firstName = "Merijn";
order.lastName = "van Mourik";
order.email = "mmourik(at)gmail(dot)com";
order.sku = "1234";

IBus bus = ServiceBus.Bus;

bus.Send(order);

Get me to the backoffice!

The order is just a plain old data transfer object, a class. Then the bus.Send() does the magic. 

The bus.Send() can also be used from inside a MVC controller. Then it would look like this:

public class OrderConfirmationController : 
    Umbraco.Web.Mvc.RenderMvcController
{
    public IBus bus { get; set; }

    private static readonly ILog Log = LogManager
        .GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

    public override ActionResult Index(RenderModel model)
    {
// .....
	bus.Send(order);
// .....
    }
}

Inject me!

With NServiceBus the bus.Send() magic comes to reality!

NServiceBus takes the responsiblity for sending data over the wire. It's just like how ethernet cards wire PC's to the local area network. You configure some addresses and NServiceBus does the job. It uses MSMQ as transport mechanism, but can use other mechanisms as well. It can also take care of scheduling and long-running processes. It just injects itself in your code, and your code stays neat and clean!

Before I dive into the code further. For me 2013 was a year when I found out about some amazing technologies. I got certified under guidance of Per and Sebastiaan. Next I built my first e-commerce website with Umbraco and TeaCommerce. I met those unicorns doing nasty stuff with HTML. Thanks Per for introducing me to AngularJs. I had loads of fun with TeaCommerce, I got certified on that too. Thanks Anders! It also was the year where I found out how to get rid of batch processing. Thanks Udi Dahan for introducing me to NServiceBus. Thanks community for building great open source software. Which makes my life fun.

Now let's get my feet back on the ground. How to inject NServiceBus right into the Umbraco controllers and event handlers? How to transport your business data to the backoffice - the easy way?

First we need to startup the bus. This is done in the startup handler of Umbraco.

public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, 
    ApplicationContext applicationContext)
{
	ServiceBus.Init();
}

Get on the bus!

The ServiceBus.Init() uses a singleton, which ensures there is only one instance at the same time. NServiceBus needs several seconds to initialize. You only want to do this once.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using NServiceBus;

namespace Umbraco.Extensions
{
    public static class ServiceBus
    {
        public static IBus Bus { get; private set; }

        public static void Init()
        {
            if (Bus != null)
                return;

            lock (typeof(ServiceBus))
            {
                if (Bus != null)
                    return;
                Bus = Configure.With(AllAssemblies.Except("sqlceca40")
                    .And("sqlcecompact40").And("sqlceer40en").And("sqlceme40")
                    .And("sqlceqp40").And("sqlcese40").And("msvcr90"))
                    .Log4Net()
                    .DefaultBuilder()
                    .ForMVC()   // <------ here is the line that 
                                // registers everything in MVC
                    .UseTransport<Msmq>()
                    .UnicastBus()
                    .SendOnly();
            }
        }
    }
}

One and only one!

NServiceBus uses a fluent API which makes it really easy to configure it. It's very well documented. At startup each and every dll inside the bin folder is scanned, so NServiceBus can inject itself. It uses AutoFac, but also other containers are supported. Some dll's are troublemakers, you can just Except them like I did.

The SendOnly() configuration is important. It will make sure the endpoint only sends messages, and skips some extra unneeded configuration. So everything stays as fast as possible. The receiving party does not have this, this will be a service endpoint that does full processing. But it does not have to be located at your Umbraco server. So you are really offload backoffice processing from your frontend server. NServiceBus has even load-balancing by default, so if you need heavy processing, you can easily add worker nodes too.

using System;
using System.Linq;
using NServiceBus;
using System.Web.Mvc;
using System.Web.Http;

public static class NServiceBusConfig
{
    public static Configure ForMVC(this Configure configure)
    {
        // Register our http controller activator with NSB
        configure.Configurer.RegisterSingleton(typeof(IControllerActivator),
            new NServiceBusControllerActivator());

        // Find every http controller class so that we can register it
        var controllers = Configure.TypesToScan
            .Where(t => typeof(IController).IsAssignableFrom(t));

        // Register each http controller class with the NServiceBus container
        foreach (Type type in controllers)
            configure.Configurer.ConfigureComponent(type, DependencyLifecycle.InstancePerCall);

        //Configure any other dependencies you need here

        // Set the MVC dependency resolver to use our resolver
        DependencyResolver.SetResolver(new NServiceBusDependencyResolverAdapter(configure.Builder));

        // Required by the fluent configuration semantics
        return configure;
    }
}

Get me my configuration!

The ForMVC() part connects NServiceBus to MVC. From where it can do it's funky stuff with dependency resolvers. 

using System;
using System.Web.Mvc;

public class NServiceBusControllerActivator : IControllerActivator
{
    public IController Create(System.Web.Routing.RequestContext requestContext, 
	    Type controllerType)
    {
        return DependencyResolver.Current
             .GetService(controllerType) as IController;
    }
}

Activate me!

With the NServiceBusControllerActivator in place, MVC is able to resolve the dependencies ot NServiceBus.

using System;
using System.Collections.Generic;
using NServiceBus.ObjectBuilder;
using System.Web.Mvc;

public class NServiceBusDependencyResolverAdapter : IDependencyResolver
{
    private IBuilder builder;

    public NServiceBusDependencyResolverAdapter(IBuilder builder)
    {
        this.builder = builder;
    }

    public object GetService(Type serviceType)
    {
        if (typeof(IController).IsAssignableFrom(serviceType))
        {
            return builder.Build(serviceType);
        }

        return null;
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        if (typeof(IController).IsAssignableFrom(serviceType))
        {
            return builder.BuildAll(serviceType);
        }
        else
        {
            return new List<object>();
        }
    }
}

Let's resolve the dependencies!

And there we have it. Apart from the controller or event handler there are 5 small files of code which do the plumbing. And it just works...

There is one little missing piece. How do CRM and ERP process the same message? This is the best part where the pub-sub pattern enters the game. Basically CRM and ERP subscribe to the message you send on the bus. And NServiceBus is just getting it done.

This all worked for me pretty well, it's a valuable extension to my toolbelt. I use it daily in a production environment where we process a lot of orders. I hope you will soon benefit from it too! I'm currently working on an example on GitHub, you can already have a look at the code. It's based upon the Hybrid Framework from Jeroen and Jeavon.

Happy coding!

Merijn

 

References:

Merijn van Mourik

Merijn is on Twitter as