To make this work, we'll be creating 3 new classes:
- NServiceBusWebApiConfig
- NServiceBusWebApiDependencyResolverAdapter
- NServiceBusHttpControllerActivator
First, we'll create the NServiceBusHttpControllerActivator class. This class will make a little more sense once we get to dependency injection using NSB's container.
using System; using System.Net.Http; using System.Web.Http; using System.Web.Http.Controllers; using System.Web.Http.Dispatcher; public class NServiceBusHttpControllerActivator : IHttpControllerActivator { public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) { return GlobalConfiguration.Configuration.Services .GetService(controllerType) as IHttpController; } }
Next, we'll create the NServiceBusWebApiDependencyResolverAdapter class. This class is an implementation of IDependencyResolver, and will be used to string everything together between NServiceBus and the Web API framework. For more information on implementing IDependencyResolver, check out this article.
using System; using System.Collections.Generic; using System.Web.Http.Controllers; using System.Web.Http.Dependencies; using NServiceBus.ObjectBuilder; public class NServiceBusWebApiDependencyResolverAdapter : IDependencyResolver { private IBuilder builder; public NServiceBusWebApiDependencyResolverAdapter(IBuilder builder) { this.builder = builder; } public object GetService(Type serviceType) { if(typeof(IHttpController).IsAssignableFrom(serviceType)) { return builder.Build(serviceType); } return null; } public IEnumerable<object> GetServices(Type serviceType) { if (typeof(IHttpController).IsAssignableFrom(serviceType)) { return builder.BuildAll(serviceType); } else { return new List<object>(); } } public IDependencyScope BeginScope() { return this; } public void Dispose() { /*No-op*/ } }
Finally, we'll create the NServiceBusWebApiConfig class that will allow us to tie all this in to NServiceBus' normal startup. This class will register our new controller activator with NServiceBus, and will set the framework's dependency resolver to our newly created one.
using System; using System.Linq; using System.Web.Http; using System.Web.Http.Controllers; using System.Web.Http.Dispatcher; using NServiceBus; public static class NServiceBusWebApiConfig { public static Configure ForWebApi(this Configure configure) { // Register our http controller activator with NSB configure.Configurer.RegisterSingleton(typeof(IHttpControllerActivator), new NServiceBusHttpControllerActivator()); // Find every http controller class so that we can register it var controllers = Configure.TypesToScan .Where(t => typeof(IHttpController).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 WebApi dependency resolver to use our resolver GlobalConfiguration.Configuration.DependencyResolver = new NServiceBusWebApiDependencyResolverAdapter(configure.Builder); // Required by the fluent configuration semantics return configure; } }
Once these classes have been created, in the Global.asax.cs file of your Web API project, add the required NSB initialization code to the Application_Start method, taking care to note the use of "ForWebApi" rather than "WithWeb".
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); Configure.With() .DefaultBuilder() .ForWebApi() // <------ here is the line that registers everything .Log4Net() .XmlSerializer() .MsmqTransport() .IsTransactional(false) .PurgeOnStartup(false) .UnicastBus() .ImpersonateSender(false) .SendOnly(); }
That's it! Now, simply add a public property or a constructor argument of type IBus to your controllers that use NServiceBus to send messages, and you're all set!