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
- Download and extract that latest stable build (Zip Archive) from
RavenDB Downloads (2750 at time of writing)
- 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.
- You should end up with this:
- Go to http://localhost:8080
- Create a new database called RavenDbDemo
Project Setup
- Run Visual studio as administrator
- Create a new MVC project
- Create a new Virtual Directory in IIS pointing to the application path
- Alter the web site's application pool's Identity to the current user
- Add RavenDb reference to the application
- Add SignalR reference
- Add the RavenDb connection string to
web.config
<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:
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)
{
}
public void OnNext(DocumentChangeNotification documentChangeNotification)
{
if (documentChangeNotification.Type == DocumentChangeTypes.Put)
{
Email newEmail;
using (var session = MvcApplication.Store.OpenSession())
{
newEmail = session.Load<Email>(documentChangeNotification.Id);
}
new EmailHub().Send(newEmail.Sender, newEmail.Subject);
}
}
}
}
Very well, now we need to subscribe to the changes in the document collection, so, in Global.asax add the function CheckForEmails()
:
private static void CheckForEmails()
{
Store
.Changes()
.ForDocumentsStartingWith("Emails/")
.Subscribe(new EmailsObserver());
}
Then make sure you call it after instantiating the Document Store:
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:
@{
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.
Then it should be shown on the web page immediately.
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 ;)