Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / IIS

Push Notifications using RavenDb and SignalR

4.56/5 (6 votes)
18 Nov 2013CPOL2 min read 33.7K  
A simple email inbox with a NoSQL database that pushes records to the client when a new document is added to the collection.

Introduction

In this article, we will implement a simple email inbox with a NoSQL database that pushes records to the client when a new document is added to the collection.

Reader is assumed to have basic knowledge of RavenDb, DocumentStore, DocumentCollection, etc... as well as basic knowledge of ASP.NET MVC and SignalR framework.

The application is very simple, meant to educate rather than impress the reader cough* Marcelo Ricardo de Oliveira cough*

Background

The Changes API offers a great functionality to subscribe to changes in Documents and DocumentCollections, however, I felt that the documentation was less than adequate, it's my goal here to provide simple working code.

Step by step instructions

RavenDb Setup

  1. Download and extract that latest stable build (Zip Archive) from RavenDB Downloads (2750 at time of writing)
  2. Get the server up and running by executing /RavenDB-Build-2750/Start.cmd if you get the exception "Cannot load Counter Name data because an invalid index '' was read from the registry", run cmd as administrator, then run command lodctr /r then rerun.
  3. You should end up with this:
  4. Image 1

  5. Go to http://localhost:8080
  6. Create a new database called RavenDbDemo

Project Setup

  1. Run Visual studio as administrator
  2. Create a new MVC project
  3. Create a new Virtual Directory in IIS pointing to the application path
  4. Alter the web site's application pool's Identity to the current user
  5. Add RavenDb reference to the application
  6. Add SignalR reference
  7. Add the RavenDb connection string to web.config
XML
<add name="RavenDB" connectionString="Url=http://localhost:8080;Database=RavenDbDemo" />

Code

To make use of the changes api, we have to create an observer class that implements IObserver<DocumentChangeNotification> to take action when a new document is added to the collection, EmailsObserver.cs does just that:

C#
using System;
using Entities;
using Raven.Abstractions.Data;
using WebUI.Hubs;

namespace WebUI.Models
{
    public class EmailsObserver : IObserver<DocumentChangeNotification>
    {
        public void OnCompleted()
        {
        }

        public void OnError(Exception error)
        {
            //ToDo:handle exception
        }

        public void OnNext(DocumentChangeNotification documentChangeNotification)
        {
            if (documentChangeNotification.Type == DocumentChangeTypes.Put)//new document inserted
            {
                Email newEmail;
                using (var session = MvcApplication.Store.OpenSession())
                {
                    newEmail = session.Load<Email>(documentChangeNotification.Id);//get document by id
                }

                new EmailHub().Send(newEmail.Sender, newEmail.Subject);//notify clients
            }
        }
    }
}

Very well, now we need to subscribe to the changes in the document collection, so, in Global.asax add the function CheckForEmails():

C#
private static void CheckForEmails()
{
    Store
        .Changes()
        .ForDocumentsStartingWith("Emails/")//monitor our Emails document collection
    .Subscribe(new EmailsObserver());
}

Then make sure you call it after instantiating the Document Store:

C#
protected void Application_Start()
{
    Store = new DocumentStore { ConnectionStringName = "RavenDB" };
    Store.Initialize();
    CheckForEmails();
    [....rest of code to register routes, filters, etc...]
}

And in our Index.cshtml:

ASP.NET
@{
    ViewBag.Title = "Inbox";
}

<h2>Inbox</h2>
<div class="container">
    <ul id="inbox">
    </ul>
</div>
@section scripts {
    <script src="@Url.Content("~/Scripts/jquery.signalR-2.0.0.js")" 
            type="text/javascript"></script>
    <script src="@Url.Content("~/signalr/hubs")" 
              type="text/javascript"></script>
    <script>
        $(function () {
            $.connection.hub.start().done(function () {

            });

            var email = $.connection.emailHub;
            email.client.addEmail = function (sender, subject) {
           
                $('#inbox').append('<li><strong>' + sender
                    + '</strong>: ' + subject + '</li>');
            };
           
        });
    </script>
}

That's it, run the application, insert a new Email in the Emails document collection.

Image 2

Then it should be shown on the web page immediately.

Image 3

Tricky Parts

I ran into some problem when implementing this project:

Exception: "This operation requires IIS integrated pipeline mode."

SignalR exception, project should be run under IIS not the VS server.

Exception: "The requested page cannot be accessed because the related configuration data for the page is invalid."

RavenDb exception, remove handler <add name="All" path="*" verb="*" type="Raven.Web.ForwardToRavenRespondersFactory, Raven.Web" /> from web.config.

Exception: "Cannot access file, the file is locked or in use"

RavenDb exception, make sure the web site's app pool has privileges.

Conclusion

That's it, hope I delivered a clear explanation and a simple application to demonstrate RavenDb push functionality. As always, let me know if you have any comments or questions ;)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)