NoSQL with RavenDB and ASP.NET MVC

nosql.png

 

For a loooong time (at least for me Zwinkerndes Smiley ) it was a fact that files have to be in a database. Usual files are saved in a relational database and linked. But in a while there exists resistance – NoSQL is the word.

What are NoSQL database?

There are several types of NoSQL database – for a first view I recommend you the Wikipedia article.

Prominent representatives are MongoDB and CouchDB.

RavenDB?

RavenDB is a quite young representative of the document database. The Quellcode is Open Source but you need a Closed-Source application licence. The developer is Ayende Rahien which Blog works with RavenDB as data source as well.

The main different to the other NoSQL databases is the well done integration into Windows & .NET platforms.

Data storage with RavenDB…

image

Different to an SQL database schema less JSON document will be saved in RavenDB. It’s also possible to apply LINQ based Indexes. The documentation is also quite good for a first entry. At least first-time user should read “Document Structure Design Considerations”.

Introduction…

image1290RavenDB could be downloaded at the Download-side. In this package are several Samples, the RavenDB server and various Client-libraries included. The most interesting folder is the “Server” folder and (at least for the introduction) the folder “Samples”.

To start RavenDB there are various options:

- As console application on Port 8080

- As Website in IIS

- As Windows service

Probably I forget something Zwinkerndes Smiley

The easiest way is the console application.

All you have to do is run the “Raven.Server.exe” in the folder “Server” (as admin!):

image

RavenDB management interface

After the start of the server should the management interface open in the browser. The RavenDB management studio is in Silverlight and it looks quite nice. In this management interface it’s possible to take a look at the documents and edit them. I think it’s related to the SQL management studio.

imageimage

image

To use RavenDB in projects…

You can get the assemblies from the download folder or you get the NuGet package.

Now to the Coding…

After we’ve talked about the concepts and the server works we are now going to talk about the Coding. Some Code-parts are from the Blogsystem of Ayende – named Raccoon.

I’ve taken some Infrastructure-code from the Raccoon project.

This code makes it easier to get access to the RavenDB and it’s easy to call from every Controller.

The following code is “Infrastructure” Code. Maybe it’s possible to make it shorter but then it’s not that classy Zwinkerndes Smiley

RavenActionFilterAttribute.cs

The attribute in my example is also integrated as Global Filter in the Global.ascx

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
            filters.Add(new RavenActionFilterAttribute());
        }

The code of the filter:

/// <summary>
    /// This filter will manage the session for all of the controllers that needs a Raven Document Session.
    /// It does so by automatically injecting a session to the first public property of type IDocumentSession available
    /// on the controller.
    /// </summary>
    public class RavenActionFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.IsChildAction)
            {
                DocumentStoreHolder.TrySetSession(filterContext.Controller, (IDocumentSession)filterContext.HttpContext.Items[this]);
                return;
            }
            filterContext.HttpContext.Items[this] = DocumentStoreHolder.TryAddSession(filterContext.Controller);
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (filterContext.IsChildAction)
                return;
            DocumentStoreHolder.TryComplete(filterContext.Controller, filterContext.Exception == null);
        }
    }

DocumentStoreHelper.cs

In fact this is where the connection to the store and the access will be warranted. I’m not sure what else the function is Zwinkerndes Smiley

 /// <summary>
    /// This class manages the state of objects that desire a document session. We aren't relying on an IoC container here
    /// because this is the sole case where we actually need to do injection.
    /// </summary>
    public class DocumentStoreHolder
    {
        private static IDocumentStore documentStore;

        public static IDocumentStore DocumentStore
        {
            get { return (documentStore ?? (documentStore = CreateDocumentStore())); }
        }

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

            return store;
        }

        private static readonly ConcurrentDictionary<Type, Accessors> AccessorsCache = new ConcurrentDictionary<Type, Accessors>();

        private static Accessors CreateAccessorsForType(Type type)
        {
            var sessionProp =
                type.GetProperties().FirstOrDefault(
                    x => x.PropertyType == typeof(IDocumentSession) && x.CanRead && x.CanWrite);
            if (sessionProp == null)
                return null;

            return new Accessors
            {
                Set = (instance, session) => sessionProp.SetValue(instance, session, null),
                Get = instance => (IDocumentSession)sessionProp.GetValue(instance, null)
            };
        }

        public static IDocumentSession TryAddSession(object instance)
        {
            var accessors = AccessorsCache.GetOrAdd(instance.GetType(), CreateAccessorsForType);

            if (accessors == null)
                return null;

            var documentSession = DocumentStore.OpenSession();
            accessors.Set(instance, documentSession);

            return documentSession;
        }

        public static void TryComplete(object instance, bool succcessfully)
        {
            Accessors accesors;
            if (AccessorsCache.TryGetValue(instance.GetType(), out accesors) == false || accesors == null)
                return;

            using (var documentSession = accesors.Get(instance))
            {
                if (documentSession == null)
                    return;

                if (succcessfully)
                    documentSession.SaveChanges();
            }
        }

        private class Accessors
        {
            public Action<object, IDocumentSession> Set;
            public Func<object, IDocumentSession> Get;
        }

        public static void Initailize()
        {
            //RavenProfiler.InitializeFor(DocumentStore,
            //    //Fields to filter out of the output
            //    "Email", "HashedPassword", "AkismetKey", "GoogleAnalyticsKey", "ShowPostEvenIfPrivate", "PasswordSalt", "UserHostAddress");

        }

        public static void TrySetSession(object instance, IDocumentSession documentSession)
        {
            var accessors = AccessorsCache.GetOrAdd(instance.GetType(), CreateAccessorsForType);

            if (accessors == null)
                return;

            accessors.Set(instance, documentSession);
        }
    }

BaseController for all Controllers which want to access on the RavenDB

To get access to the RavenDB on the Controller we will make a BaseController which has all iDocumentSessions as Property:

Till this part the Code is “Ayende” checked because it’s from the Racoon-Blog – so it should be good Zwinkerndes Smiley

An easy model

I’ve chosen a very simple model without any connections to other objects. This will follow later on.

public class Word
    {
        public Guid Id { get; set; }
        public string Value { get; set; }
        public string Description { get; set; }
        public string LcId { get; set; }
        public int UpVotes { get; set; }
        public int DownVotes { get; set; }
    }

CRUD with RavenDB

public class WordsController : BaseController
    {
        public ViewResult Index()
        {
            var words = Session.Query<Word>().ToList();
            return View(words);
        }

        //
        // GET: /Words/Details/5

        public ViewResult Details(Guid id)
        {
            Word word = Session.Load<Word>(id);
            return View(word);
        }

        //
        // GET: /Words/Create

        public ActionResult Create()
        {
            return View();
        } 

        //
        // POST: /Words/Create

        [HttpPost]
        public ActionResult Create(Word word)
        {
            if (ModelState.IsValid)
            {
                Session.Store(word);
                Session.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(word);
        }

        //
        // GET: /Words/Edit/5

        public ActionResult Edit(Guid id)
        {
            Word word = Session.Load<Word>(id);
            return View(word);
        }

        //
        // POST: /Words/Edit/5

        [HttpPost]
        public ActionResult Edit(Word word)
        {
            if (ModelState.IsValid)
            {
                Session.Store(word);
                Session.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(word);
        }

        //
        // GET: /Words/Delete/5

        public ActionResult Delete(Guid id)
        {
            Word word = Session.Load<Word>(id);
            return View(word);
        }

        //
        // POST: /Words/Delete/5

        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(Guid id)
        {
            Word word = Session.Load<Word>(id);
            Session.Delete(word);
            Session.SaveChanges();
            return RedirectToAction("Index");
        }
    }

All in all – totally easy. Let’s see how it goes on…

Result

That’s it about the introduction to RavenDB. This is just a small infrastructure that makes it easy to get in touch with RavenDB. You will find the whole Source Code on Codeplex in BusinessBingo Repository.

Links

Of course I recommend you the blog of Ayende – there are some posts of RavenDB. Also there are some RavenDB tutorials. And if that’s not enough take a look on the page of Rob Ashton.


If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.

About the author

Written by Code Inside Team

Learn more about our team.

2 Responses

Comment on this post

Recent Posts

  • Automated Security Analyser for ASP.NET websites

    Evil Hackers are lurking everywhere and many Web-applications are delicately and share “too much” with the attacker. A quick (first!) overview offers the Tool “ASafaWeb”. All the website does is making a few requests and writing an Analyses including problem solving’s. There are no permanent disadvantages (bad requests/ DoS attacks and so on). Example: KnowYourStack.com ...

  • image1489-570x194.png
    „Sign in with Twitter“ for your own ASP.NET WebApp

      “Sign in with Twitter” is a popular practice to authenticate the users on your website. One advantage compared to an own registration is the lower inhibition for the user. But on the other hand Twitter doesn’t fess up with all the information’s and you will get into a kind of addiction. At the end ...

  • image1485-570x194_thumb.png
    CodePlex is going to be updated

      CodePlex the Microsoft Open Source Project Hosting Plattform hasn’t changed that much in the last few years and for a few times I thought Microsoft stopped the whole developing process. But now I found out that there is still life in the project. Maybe it is because of the success of GitHub or because ...

  • image1474_thumb.png
    What does Adobe in the flash-free web? Magazine-Style Layouts with CSS Regions!

      Adobe is well known for Photoshop and Flash but of course there is a lot more. According to the “Future Post” from Google Adobe declared one of their big subjects on a Blogpost. I’m talking about the W3C Working Draft to CSS Regions. Adobe cooperates with the WebKit Team and W3C on this. What ...

  • image1471-523x194.png
    HTML 5 Games, Tooling & 3D

      Game Developing is an interesting subject for all kind of software developer. But as a web developer without any Flash-skills there aren’t that much starting points. With HTML5 and the combination between Javascript, CSS3 and fast browsers there are the first “robust” HTML5 games. HTML5 games? Is this real? Neowin created a “Top 10” ...

Support us