ASP.NET Web API with RavenDB and Castle.Windsor
I had an idea for a project and decided I wanted to give RavenDB and the new ASP.NET Web API a try.
The following is a description on how I hooked up RavenDB to Castle Windsor to inject new IDocumentSession objects into ApiController objects per web request. ASP.NET Web API and RavenDB are both new to me, so if you see anywhere this can be improved on, or if I’m just doing it wrong, please let me know.
First of all we need to initalise RavenDB, this is really pretty simple, we just need to create a DocumentStore object and call Initialize on it once for the entire application, this DocumentStore object must be made available so that we can use it to open sessions to the database.
var documentStore = new DocumentStore { Url = "http://localhost:8080/" };
documentStore.Initialize();
var session = documentStore.OpenSession();
We now need to register the DocumentStore object we create with Castle Windsor so we can access it once per web request to open a session. To do this we’ll build a class which derives from IWindsorInstaller. This class will be responsible for all the dependency injection relating to RavenDB. I personally like using installer classes as it separates our code relating to DI away from other initialisation code.
To start with we need to implement the interface by writing an Install method. When this method is called, Castle Windsor passes in an IWindsorContainer object which we will use to register our RavenDB related dependencies. To start with, we’ll register the IDocumentStore object.
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IDocumentStore>()
.Instance(CreateDocumentStore())
.LifeStyle.Singleton);
}
private static IDocumentStore CreateDocumentStore()
{
var documentStore = new DocumentStore { Url = "http://localhost:8080/" };
documentStore.Initialize();
return documentStore;
}
Here we create a DocumentStore object and register it with Windsor, we register the object with a singleton lifestyle type as we only need one of these objects for the application.
Next we need to register the IDocumentSession type.
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IDocumentStore>()
.Instance(CreateDocumentStore())
.LifeStyle.Singleton,
Component.For<IDocumentSession>()
.UsingFactoryMethod(GetSession)
.LifeStyle.PerWebRequest);
}
private static IDocumentSession GetSession(IKernel kernel)
{
var documentStore = kernel.Resolve<IDocumentStore>();
return documentStore.OpenSession();
}
Here we define a factory method which uses an IKernal object to resolve the IDocumentStore singleton which we registered previously and use it to open a new session. In the Install method we specify that a new IDocumentSession should be created for each web request.
Okay, so now whenever we need a database session, we can just ask Castle Windsor to give us one any we’re ready to go.
The next thing we need to think about is how we’re going to do this. Our aim is to have access to new database sessions per web request in our ApiControllers. I don’t want the controllers to be responsible for resolving their dependencies, so we need to inject them.
To do this, we’re going to get Castle Windsor to build our ApiController objects for us.
First of all we need to tell Castle Windsor about our controllers, so that when one is requested, Windsor is able to resolve all dependencies and provide the required controller.
public class ControllersInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
AllTypes
.FromThisAssembly()
.BasedOn<IHttpController>()
.Configure(c => c.LifeStyle.Transient
.Named(c.Implementation.FullName))
);
}
}
Like before we’re using an installer class to register our types. The ApiController classes we write to build our web api all implement the IHttpController interface, and this is the type that’s required when a request comes in, so this is the type we need to register with Windsor. In this method, we’re asking Windsor to look for and register all types in the current assembly, that implement IHttpController.
Now that Castle Windsor knows about our data access classes and controllers, we need to replace the Default Http Controller Factory with a custom controller factory which will use Castle Windsor to build our IHttpController objects.
To do this, we need to write a class that implements the IHttpControllerFactory interface.
The IHttpControllerFactory interface is pretty simple, it just requires us to implement methods to create and release controllers. The CreateController method passes in a context and name of the controller which is required, we must take this name and use it to resolve the required controller type from Windsor. Before we do this, we need an IKernal object from Windsor, this is a dependency of the class we’re building, and we required it to be injected into our constructor.
public class WindsorHttpControllerFactory : IHttpControllerFactory
{
private readonly IKernel _kernel;
public WindsorHttpControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
Now we have our IKernal object, we can use it to get at the controllers we registered earlier.
Right, lets build out controllers, to do this, we must complete two steps, first of all we must get the required IHttpController object.
public IHttpController CreateController(HttpControllerContext controllerContext, string controllerName)
{
var controller = _kernel.Resolve<IHttpController>(String.Format("Web.Api.Controllers.{0}Controller", controllerName));
The controllerName string which is passed in is not the fully qualified name, so we build up the full name and resolve the controller from Windsor, and we now have our controller to return!
The next step is not obvious, we need to create a controller descriptor, which is part of the controllerContext which is passed into the method. This is discussed further in this thread. Fortunately, we don’t have to do too much work, here is the full method.
public IHttpController CreateController(HttpControllerContext controllerContext, string controllerName)
{
var controller = _kernel.Resolve<IHttpController>(String.Format("Web.Api.Controllers.{0}Controller", controllerName));
controllerContext.Controller = controller;
controllerContext.ControllerDescriptor = new HttpControllerDescriptor(GlobalConfiguration.Configuration, controllerName, controller.GetType());
return controllerContext.Controller;
}
Right, now we have our new http controller factory we need to register it with Windsor so that our dependency on IKernal can be resolved and injected when we come to use it. We’ll do this in the ControllersIntaller class we wrote earlier, we just need to simply register it as a singleton.
public void Install(IWindsorContainer container, IConfigurationStore store)
{
Component.For<IHttpControllerFactory>()
.ImplementedBy<WindsorHttpControllerFactory>()
.LifeStyle.Singleton
Now we’ve setup Windsor as we require, all we need to do is create our IWindsorContainer object and tell ASP.NET to use our WindsorHttpControllerFactory. We do this in the Global.asax.cs file.
protected void Application_Start()
{
//Code removed
InitialiseWindsor();
var configuration = GlobalConfiguration.Configuration;
configuration.ServiceResolver.SetService(
typeof(IHttpControllerFactory),
_container.Resolve<IHttpControllerFactory>());
}
protected void InitialiseWindsor()
{
_container = new WindsorContainer()
.Install(FromAssembly.This());
}
With all this in place, when writing a new ApiController we can simply request a IDocumentSession object in our constuctor as use it as we wish.
public class SuperController : ApiController
{
private readonly IDocumentSession _documentSession;
public SuperController(IDocumentSession documentSession)
{
_documentSession = documentSession;
}
Hope that helps!
Categorised as: ASP.NET Web API