Wednesday, October 27, 2010

RavenDb, ASP.NET MVC and Windsor working together

I’m putting together a new project, TardisBank.com, using RavenDb, ASP.NET MVC and Windsor. It’s up on github here:

http://github.com/mikehadlow/Suteki.TardisBank

Here’s how I wire up Windsor and RavenDb.

First, in Global.asax.cs I initialise the container and ask it to load and run installers from all the application assemblies:

public class MvcApplication : System.Web.HttpApplication, IContainerAccessor
{
    ...

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
        InitialiseContainer();
        InitialiseControllerFactory();
    }

    protected void InitialiseContainer()
    {
        if (container == null)
        {
            container = new WindsorContainer()
                .Install(
                    FromAssembly.InDirectory(new AssemblyFilter(HttpRuntime.BinDirectory, "Suteki.*.dll")));
        }
    }

    protected void InitialiseControllerFactory()
    {
        var controllerFactory = container.Resolve<IControllerFactory>();
        ControllerBuilder.Current.SetControllerFactory(controllerFactory);
    }

    static IWindsorContainer container;
    public IWindsorContainer Container
    {
        get { return container; }
    }
}

One of the installers it runs is my RavenInstaller:

public class RavenInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component.For<IDocumentStore>().Instance(CreateDocumentStore()).LifeStyle.Singleton,
            Component.For<IDocumentSession>().UsingFactoryMethod(GetDocumentSesssion).LifeStyle.PerWebRequest
            );
    }

    static IDocumentStore CreateDocumentStore()
    {
        var store = new DocumentStore
        {
            ConnectionStringName = "tardisConnection"
        };
        store.Initialize();
        return store;
    }

    static IDocumentSession GetDocumentSesssion(IKernel kernel)
    {
        var store = kernel.Resolve<IDocumentStore>();
        return store.OpenSession();
    }
}

Because Windsor already provides a global application store for both singleton and per-request components, we can give it the responsibility of handling the instantiation and lifecycle of the DocumentStore and DocumentSesssion. The DocumentStore is created and initialised once the first time it is requested. The DocumentSession has a PerWebRequest lifestyle and is created using a factory method the first time it is requested.

Don’t forget to register the PerRequestLifestyleModule in Web.config:

<system.webServer>
  <validation validateIntegratedModeConfiguration="false"/>
  
  <modules runAllManagedModulesForAllRequests="true">
    <add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor" />
  </modules>
</system.webServer>

Windsor will properly dispose both the DocumentStore when the application closes and the DocumentSession at the end of each request.

5 comments:

GeeBee said...

Sounds like you've been having fun! Will you be making this (or is it already) open sourced so we can see it all working together?

Mike Hadlow said...

Hi GeeBee,

Yes, I plan to launch it next Tuesday at £5App here in Brighton. It will go on GitHub some time before then.

Krzysztof Ko┼║mic said...

RavenDB and Windsor in one project? You have just one potential interested contributor here :)

Mike Hadlow said...

Hi Krzysztof,

Excellent, I'd love to get your input. I'll make a point of hubbing it ASAP.

There's really not much to look at yet. It's really just me playing :)

Mike Hadlow said...

OK, The code is now available at:
http://github.com/mikehadlow/Suteki.TardisBank