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.

6 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

ByteBlast said...

Thank you for this post Mark. By now it is quite old but the information is still very relevant today.

I am doubtful that I will get an answer from you given the age of this post; but I have a couple of questions and if you can find the time, I would be very grateful if you could answer them.

1. Why do I need to edit Web.config. What will happen if I do not and is there any way to achieve the same thing using code?
2. What is the recommended way to call SaveChanges when the session is disposed?

Thank you.