Building an ASP.NET MVC app using RavenDB as a Backing Store

Posted by: Sumit Maitra , on 2/22/2012, in Category ASP.NET MVC
Views: 114264
Abstract: In this article, we will see how to build an ASP.NET MVC app using RavenDB Embedded and then publish it to a hosted source.

In a previous article, I had demonstrated how we could introduce RavenDB as an auto-save cache for information that resides in a traditional RDBMS. Today we are going to look at how we can use it as the only backing store of an ASP.NET MVC application.

Note: If you are new to NoSql or RavenDB or Document Databases, make sure you read Hello RavenDB! Introducing RavenDB for .NET Developers

Using RavenDB as a backing store is actually very easy. In a development environment, all you have to do is install using Nuget package manager and start the Raven.Server.exe from the packages folder. However in a production environment, you may or may not be able to run an additional HTTP server for yourself. If you have a hosting provider where your site is shared with multiple other sites, you may not have the access to run a separate HTTP server. Beauty of RavenDB is that even in such a constrained environment, you can easily run RavenDB and not require SQL Server backend. RavenDB has special embedded variant that allows you to run RavenDB in medium trust.

 

In this article, we will see how to build an ASP.NET MVC app using RavenDB Embedded and then publish it to a hosted source.

Again for simplicity purposes we will take our tried and tested Blog example. The blog data model is simple enough to do quickly but deep enough to explain basic relationships.

1: Start with a usual ASP.NET MVC, Internet project template

create-new-project

2. Add RavenDB (Embedded) reference using the Package Manager (Tools > Extension Manager).

add-raven-embedded-reference

3. Review the License Agreement. RavenDB is NOT free for commercial use. Accept the license to complete installation.

accept-raven-license

4. Add a class library project to the solution. Call it RaBlog.Service.

5. Modeling the Blog Document database. To start of with we will consider a very simple model

image

- Add all the classes in a Model folder.

Note: The ‘Comment’ object is typically not a part of the Blog Post update. We will see how we have to use a workaround because of this. In a future post, we will see how to use a ‘denormalized’ document structure. For now, let’s focus on using the embedded version to publish a live site.

6. With the Model out of the way, let's look a different way of implementing persistence layer, one without a repository pattern.

RavenDB backing store is represented by the DocumentStore object. It implements the IDocumentStore interface. Every 'connection' to the DocumentStore is a RavenDB DocumentSession. This implements the IDocumentSession interface. To build our RavenDB access layer we will do the following

- Create a RavenController class that inherits from the MVC's Controller class.

add-raven-controller

- We will inject the instance of IDocumentStore and instead of using the MVC provided HTTPServerUtility.Session object we will hide it by using the new keyword and add a Session of type IDocumentSession.

override-mvc-session-by-raven-doc-session

- We override the OnActionExecuting method. This is called just before the action begins execution.

We will use OpenSession in this method. OpenSession is akin to document connection open in ADO.NET. So just before the Action Execution starts we open a connection to our RavenDB store

override-on-action-executing

- We override the OnActionExecuted method. This is called once the action is executed. In this method we will check if there is an error, if not, the document session is saved. This saves whatever entities we put in the RavenDB's document Session.

override-on-action-executed

- The simplicity of this pattern is we don't have to explicitly call the RavenDB's document Save method in any of our controllers. Any object we put in the session will get persisted once the action completes. On the flip side, this couples data persistence to the View layer. So use it with caution.

7. With our base controller ready we move on to the HomeContoller and change it to inherit from RavenController instead of Controller and add a constructor.

override-home-controller-to-inherit-from-raven

8. We load a single 'row' of data from RavenDB by making the following call in our controller.

get-single-blog-from-raven

Example here is of the Details action that pulls up a particular Blog Post. The Session property is here the same as the one we defined in RavenController earlier. It is of type IDocumentSession. Hear the Load<T> method loads the required Document type from RavenDB. In our case it's the Blog with the id as provided in the id parameter.

9. Similarly, entire list of Blogs can be loaded as follows

load-all-blogs-from-raven

10. Updates are recorded as follows. We load the existing Blog from the session again, using the current blog’s id. Update the Title and Content and store it into the Session. Remember the ActionExecuted override from earlier? That gets called once this method finishes and thus Save is called which persists changes to the database.

home-controller-post-edit-action

Note: RavenDB’s document session does not do partial updates to the document. If we directly put the blog object passed to the action method in session store, since it does not have the related Comments, RavenDB will assume the comments have been deleted and will do the same in the database.

In future we will see how to ‘denormalize’ objects and resolve this issue.

11. I am not detailing the UI changes for Index/Add/Edit/Delete. They are standard MVC strongly typed views. I have made some HTML/CSS changes to make them look a little pretty. However we will look at the Details page where we will show the Comments that were made for the blog.

12. Implementing the Details view.

- The Details view will be actually the entire post and hence will present users with the opportunity to view existing comments and add their own comments if required.

- We update the Details.cshtml to show the user comments that have already been posted

render-all-comments-in-details-view

- Next we add a Partial View called CreateComments.cshtml. We can use the Add New View wizard and Select the ‘Comments’ Entity and the ‘Create’ template

image

- We make some cosmetic changes to make it look nicer. The final markup for CreateComments.cshtml is as follows:

create-comments-partial-view

- Now update the Details.cshtml to show the Partial View in the Details Page. We pass a new instance of the Comment object with the current Blog Id to the child partial view.

include-partial-view-in-details

- In the Controller we need to handle the POST from the CreateComments view.

- We add the following code to handle the POST

post-details-action

  • We load the current blog instance from the Session.

  • Check if the blog previously contained comments or not. If not initialize it.

  • Add the comment object and store the entire blog into the Session.

  • When this method completes the overloaded ActionExecuted method is called which saves the changes to the Store.

13. Finish off with the composition root and controller factory to inject the DocumentStore object. You can review the theory behind this pattern in my DI Introduction post.

14. Point of interest for us in this is the CreateControllerFactory() method in CompositionRoot.

if-debug-in-create-controller-factory

15. As seen above we are creating an instance of the EmbeddableDocumentStore() and giving it the ConnectionStringName. The connection string is defined in web.config. It is added when you install RavenDB from the package manager. The value looks as follows:

raven-db-embedded-connection-string

16. Notice the single statement inside a compiler directive allowing it to be applicable only for DEBUG builds.

if-debug-use-embedded-httpserver

This enables an embedded HttpServer that allows you to run the RavenDB console. Setting this to true requires your account to have netsh access to the port on which it tries to run. This may not be possible in production so we are disabling the admin console for now. In my case, my host does not allow netsh to port 8080 and if the pre-processor directives are not there you will get an Access Denied exception at run-time.

Even in Dev environment if Visual Studio is not running in Administrator mode you will get the above error. Solution for it is to run the following command in an Administrator mode, console:

netsh http add urlacl url=http://+:8080/ user="<your domain>\<your user id>"

17. With the Application built and ready to roll, switch to a Release build and build the project. Publish it to your production server through your established processes. I used Solution Explorer > RaBlog > Right Click > Publish to bring up my publish profile and push the changes using my publishing profile.

publish-profile

18. Hit publish and wait for the upload to complete. Navigate to the URL location and you should see the Home Page. There you go, you have successfully created and published an application using embedded RavenDB. This sample application is running at http://blog.sumitmaitra.com/

Note: If you are getting the yellow screen of death, turn off custom errors and checkout the error details.

Conclusion

We saw how we can use Embedded RavenDB to build and publish our own ASP.NET MVC application with very little effort.

The entire source code of this article can be downloaded over here

RavenDB on the Cloud

Hibernating Rhinos (the authors of RavenDB) have just launched a public beta of RavenDB on the cloud called RavenHQ. Currently the beta is available only for apps deployed to AppHarbor. Check it out if you want to.

http://ayende.com/blog/154785/ravenhq-goes-betandash-ravendb-reaches-the-cloud

https://appharbor.com/addons/ravenhq

Disclaimer: www.dotnetcurry.com is not associated with Hibernating Rhinos or AppHarbor.

Give a +1 to this article if you think it was well written. Thanks!
Recommended Articles
Sumit is a .NET consultant and has been working on Microsoft Technologies since his college days. He edits, he codes and he manages content when at work. C# is his first love, but he is often seen flirting with Java and Objective C. You can follow him on twitter at @sumitkm or email him at sumitkm [at] gmail


Page copy protected against web site content infringement by Copyscape


User Feedback
Comment posted by Yaakov Ellis on Wednesday, March 7, 2012 2:27 AM
Why are you hiding the regular HTTPServerUtility.Session object? The Session object's regular behavior is that data stored within is only accessible to this user (and only until the session expires). RavenDB data however is available to all users and persisted between sessions. So using it as a replacement for Session can be confusing to a user who expects the Session to act a certain way.
Comment posted by Sumit on Wednesday, March 14, 2012 3:35 AM
Yaakov, if you intend to use Session as a scratchpad for temporary objects, following the more conventional repository pattern is a better idea instead of overriding the Controller (refer to my previous RavenDB post).

Using it in a way depicted above simply makes assumptions on how you want to save data and it's a very neat abstraction from the point of not having to care about explicit saves. Any action on a controller that derives from RavenController, will try to persist to RavenDB whatever objects were put in the session (unless there is an error).

I don't have a preference of one over other, except that setting up a repository using DI takes up a bit more work hence is suitable for bigger and more complex projects. For a quick prototype this is a pretty good pattern to follow.
Comment posted by Justin on Saturday, March 31, 2012 1:20 PM
So I get the non-relational love for the ms mvc stack and it sounds exciting. What I do not get is why should a .NET developer like me invest time in a nonrelational data store that mimics data-management techniques?
Comment posted by Sumit on Monday, April 2, 2012 2:29 AM
@Justin Ease of use comes to my mind first thing. We have in the past done a lot of shoe-horning of Object structures into relational systems. Document datastores like Raven take that out completely.

Given, non-relational data stores are a nascent technology for day to day use, but RavenDB is a very very good start.

Another reason is these systems are now being written fresh and they are being written to solve problems we didn't have 30 years ago when RDBMS systems started maturing. I am talking about scaling. Scaling in traditional systems have always been a pain, and today data being generated/collected and analyzed is at a level where RDBMS systems are failing.

I haven't talked about RavenDB's scaleout capabilities yet, but that's just another of the factor why I would invest my time in non-relational system.

That said, it's always, horses-for-the-courses so pick and choose, choice is GOOD! :-)
Comment posted by Sumit on Wednesday, May 2, 2012 11:36 PM
Dear Readers,
Apologies for the downtime on the http://blog.sumitmaitra.com sample site. There was an unfortunate technical glitch because of which the site is currently un-available. We are working on getting alternatives up for you.
Thanks and Regards,
Sumit.
Comment posted by Sam Naseri on Monday, July 9, 2012 8:49 PM
Thanks for the great article. However, there is a thing which confuses me. In step 5 the BlogPost is defined without having Comments property, but the following codes assume such a property exists.
Comment posted by Roberto on Wednesday, October 10, 2012 3:15 AM
I tryied to deploy an MVC applicaiton with embedded ravendb on a medium trust host but it does not work. it works only on full trust enviroment
Comment posted by academic writing service on Saturday, October 13, 2012 1:01 AM
Could you either provide a downloadable version of the code or make it selectable on this page?  Thanks.
Comment posted by anil on Monday, June 24, 2013 12:54 PM
In the same why how to insert,update and delete images into database using MVC,
Plese give me one simple example on this
Comment posted by Piotr Kula MCPD on Wednesday, May 28, 2014 7:32 AM
Very good article! Will get some new projects running with RavenDB for experience. I, personally love how you used the Session to save data to the database. In MVC there is the TempData that can be used for page to page, but really, since i started using MVC, Sessions and TempData was out the door and kept away with a 10 foot barge pole. Yucky ASP days....

Post your comment
Name:  
E-mail: (Will not be displayed)
Comment:
Insert Cancel