Using RavenDB in an ASP.NET MVC website

by Hibernating Rhinos

A short, instructive tutorial, guiding step-by-step how to correctly use RavenDB from your ASP.NET MVC website

Using RavenDB in an ASP.NET MVC website

Using RavenDB from your ASP.NET MVC website is actually quite simple.

First install RavenDB to your project from nuget or the distribution packages. A detailed guide on how to do that can be found here.

Once you have RavenDB installed, there are only 2 things you need to do: creating a singleton document store, and creating way for RavenDB sessions to be created and closed.

Creating the document store

The DocumentStore object is not cheap to create, and therefore needs to be created only once per application.

First, declare a static IDocumentStore instance in your application. The easiest way to do that is to add the following somewhere in your global.asax.cs file:

    
    public static DocumentStore Store;
    

In the Application_Start() method of your global.asax.cs file, have the following:

    
    
                Store = new DocumentStore { ConnectionStringName = "RavenDB" };
                Store.Initialize();
                    
                IndexCreation.CreateIndexes(Assembly.GetCallingAssembly(), Store);
    

The first 2 lines initialize the DocumentStore using a connection string named RavenDB, and the third line automatically creates all indexes that are declared in your code.

If you installed RavenDB from nuget, the connection string was already added for you. If not, you will need to add the following to your web.config, or insert the connection parameters in the code itself:

    
          <connectionStrings>
            <add name="RavenDB" connectionString="Url=http://localhost:8080" />
          </connectionStrings>
    

This connection string expects a RavenDB server to be listening on the local 8080 port. You can execute the Raven.Server.exe executable from your RavenDB installation folder.

For Embedded mode you will need to configure a DataDir instead.

Now lets look at configuring the session lifecycle.

Managing sessions

Sessions are very cheap to create, but we want to avoid writing unnecessary code in our Controllers. For that end, we will create a RavenDB session when an HTTP session starts, and dispose of it once it ends. Before disposing of the session we will call SaveChanges(), and that will assure all changes will be persisted.

All it takes is the following code in the abstract base Controller which all your application Controllers inherit from:

    
    
        public IDocumentSession RavenSession { get; protected set; }
    
        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            RavenSession = MvcApplication.Store.OpenSession();
        }
    
        protected override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (filterContext.IsChildAction)
                return;
    
            using (RavenSession)
            {
                if (filterContext.Exception != null)
                    return;
    
                if (RavenSession != null)
                    RavenSession.SaveChanges();
            }
        }
    

To make things even cleaner, create an abstract controller named RavenController having this code, and derive all your Controllers from it. Everything will be handled seamlessly for you, and you will now have RavenSession available to query or persist with.

Routes

The convention for document IDs in RavenDB is to have both the collection name and an integer value separated by a slash, like this: {collection name}/{integer}. This may cause issues with ASP.NET MVC routing for actions like "Read" or "Delete" requiring a document ID, mainly because of the slash.

The easiest way to get around this is to have your controllers use the version of session.Load<>() accepting an integer. This function will automatically translate the integer value to the fully qualified document ID, and then use it to perform the load operation. This will allow you to write a controller accepting a non-string ID, and therefore just be able to use the default routing rules of ASP.NET MVC:

    
    public ActionResult Read(int id)
    {
         var obj = RavenSession.Load<MyClass>(id);
    
         return View(obj);
    }
    
Comments add new comment

The comments section is for user feedback or community content. If you seek assistance or have any questions, please post them at our support forums.

Mike N
reply Posted by Mike N on

Perhaps it's not obvious however you'll need to add:

using System.Reflection; using Raven.Client; using Raven.Client.Document; using Raven.Client.Indexes;

Jon
reply Posted by Jon on

I think you mean create a base controller and inherit your controllers from that base. Creating an abstract controller will mean all controllers need to have the same set of code in it.

Ayende Rahien
reply Posted by Ayende Rahien on

You are correct, I updated the text to reflect that.

Vincenzo
reply Posted by Vincenzo on

I do not like inheriting from other base class than standard Controller. However this is a fantastic project.

Ayende Rahien
reply Posted by Ayende Rahien on

Nothing forces you to, you can handle that in other ways.

This is merely a suggestion of how to do it.

John Gietzen
reply Posted by John Gietzen on

For example, you can use dependency injection to give your controller the document store in its constructor. I have tried this with both Castle and Ninject and it works beautifully.

Sidar Ok
reply Posted by Sidar Ok on

You can also add that code in the End_Request of Global.asax. But FilterContext will not be available, so you will need to use Server.GetLastException() if you want to not commit changes in case of exceptions.

Nick Meldrum (http://nickmeldrum.com)
reply Posted by Nick Meldrum (http://nickmeldrum.com) on

Or you can implement it as a custom action filter - this way you can decorate only the actions or controllers that need a Raven session opened. It will be basically the same "OnActionExecuting" and "OnActionExecuted" code as above, but in an action filter instead of applied in your Base Controller class. http://msdn.microsoft.com/en-us/library/dd381609.aspx

dashang
reply Posted by dashang on

can i get the source

Finne
reply Posted by Finne on

Excellent article, this helped me set up RavenDB in my MVC project. Thanks!

Yaron
reply Posted by Yaron on

In a typical Save action I want to return the new Id assigned back to the client. How can this be achieved while keeping this pattern ?

Yaron
reply Posted by Yaron on

There is a problem with this pattern in case I want to return the new Id as an action result.

mack
reply Posted by mack on

RavenDB is great but those samples are not for real world applications. In the real world we use mvc as presentation layer and he has nothing to do with ravendb or mongodb. Do you have any sample how to embed RavenDb in a DAL with repository pattern? I know it`s not that difficult to do, but those "hello world"ish samples are misleading. But, I still love RavenDb and wish everyone will get serious when it comes to how to use it!

Luis Vasquez
reply Posted by Luis Vasquez on

Hello, I want to share a little example how to configure RavenDB with ASP MVC using Dependency Injection, also you can download the source code for the example http://lvasquez.github.io/2014/07/20/RavenDB-ASP-MVC-DI/

SUBMIT COMMENT