Sunday, May 6, 2012

Running RIA Services on the top of Raven DB

In this post I will describe how to integrate RIA Services with document database called Raven DB. If you are not familiar with those frameworks watch this video and this one (my 2 presentations in polish). RIA Services integrates very easily with relational database by providing base implementations of domain services out of the box. Using the same pattern I have created the base implementation for services working with Raven DB. We will see later in this post what exactly the domain service is and how we can use it to build n-tier business application, but now let’s look at the Raven DB API. Let’s say we have the following data model:

Once we know how the Raven DB works we can look at the RIA Services. RIA Services gives us tools (Visual Studio extensions) and libraries that allow us to build n-tier business solution with the Silverlight or JavaScript application as a client and .Net Web Service as a server. We start building RIA Services solution from the domain service which is just a class deriving directly from DomainService or any other derived class depending on the type of a data store.

If the relation database is a data store then we can use LinqToSqlDomainService, LinqToEntitesDomainService or DbDomainService (LINQ to Entities Code First approach). TableDomainService class allows us to store data inside Windows Azure Table. If we want to store data inside any other kind of data source we have to derive directly from the DomainService class. My base service called RavenDomainService derives from DomainService and it encapsulates the logic of initializing and saving the data inside Raven DB. Let’s look at the sample usage of this class:

After adding “WCF RIA Services link” from the Silverlight project to projects containing domain service implemented above and rebuilding the whole solution, Visual Studio will generate appropriate code on the client side and we are ready to write code very similar to that presented earlier:

RIA Services gives us a very nice implementation of Unit Of Work and Identity Map patterns so the code using DAL frameworks like LINQ to SQL, LINQ to Entities, NHibernate or Raven DB is very similar to that written on the client side. There is one thing worth mentioning at this point, RIA Services needs to know which property identifies the entity object. I didn’t show you how to do it yet but it will be presented in a moment, I am writing about it here because without this little hint, the code above wouldn’t even compile.

The last thing I would like to explain is how the optimistic concurrency pattern has been implemented in case of Raven DB. Raven DB has metadata mechanism which means that each JSON document besides the actual data has additional information like document type, last modification time, etag and so on. Etag is a single value of type Guid and its goal is very similar to Timestamp or Row Version column data type in SQL Server. Raven DB server changes the value of Etag internally every time the document is changing. With this Raven DB client API allows us to enable optimistic concurrency checking on the session object level via UseOptimisticConcurrency property. There is one problem when it comes to integration with RIA Services optimistic concurrency mechanism. Etag is part of the metadata instead of document itself and it is handled by the session object internally. RIA Services doesn’t have any notion of metadata information, all data is stored inside the entity objects so we need to add additional property storing etag value which will be used on the RIA Services level but on the Raven DB level this value will be mapped into etag metadata field.

Attributes like Key, Display, Required, Range, RoundtripOriginal and MetadataType are a part of the standard .net mechanism called data annotations. RIA Services similar to other frameworks like ASP.MVC or Dynamic Data uses them to define validation rules or UI controls in layout in declarative way. Key attributes tell RIA Services which property identifies the entity object, RoundtripOriginal attributes tell that the value of the property is changed on the server side so the new value should be sent back to the client after calling server method. JsonIgnore is specific to Raven DB and it means that this property should be ignore during serialization and deserialization process. IEtag interface was introduced as a marker interface so all entities implementing this interface are treated specially by listener code. Listeners are a part of Raven DB client API and we can think of them as of a client side triggers executed in various situations.For instance during JSON document conversion process (IDocumentConversionListener) or before and after document is stored inside Raven DB (IDocumentStoreListener).

IDomainServiceFactory interface allows us extend the process of creation and destruction of domain services instance on the server side. Finally let’s see how the RavenDomainService class has been implemented:

I know, I know, I hear you saying: "What did you do all this for ??? Raven DB gives you a wonderful client API for Silverlight". I totally agree with you. I am not trying to say that you should use RIA Services instead of Raven DB directly via its Silverlight API. Those two frameworks are slightly different things. They have a different functionalities, they are designed to resolve a bit different kinds of problems. Raven DB is a database system so it is focused mainly on data storage. RIA Services solves many common problems for a business n-tier application like server and client side validation, easy integration with DataGrid or DataForm UI controls, sharing common code between client and server, marshaling exceptions and so on. For me, those two frameworks can work great together and such cooperation seems to be very reasonable. I was searching google for any samples showing how to integrate them but I couldn’t find it. So I did my own !:) I hope you find it useful.