Tuesday, October 12, 2010

My Silverlight 4 Reference Architecture: Querying

After having put the introduction and the commanding part behind us, let me explain how I deal with querying. Consider the following slice of the reference architecture

clip_image001[6]

My original intention was to use WCF Data Services combined with NHibernate on the query side. For one, because it allows you to filter the result set using a subset of the LINQ functionality at the Silverlight client. But also because it will transfer the resulting entity set including any associated relationships as one network operation; which is something that WCF RIA Services can't do. In essence it means that you don't have to explicitly convert entities to DTOs, but I kept the term in the diagram

However, in reality this subset of LINQ is a bit too limited. For instance, filtering an entity set based on some criteria on one of its associations (through the Any() operation) is not possible. WCF Data Services does support Service Operations, but I have never managed to get anything other than the MSDN examples to work. In fact, the Add Service Reference does not even support service operations. That's why I introduced a dedicated WCF Query Service.

Nevertheless, having a service class with a multitude of operations, all using one of the Repositories is a great recipe for getting a bloated class. That's why every query operation is handled by a dedicated Service Action class that handles the interaction with the repositories, preferably using an implementation of the Specification pattern. Such a Specification encapsulates (a potentially very complex) query on an IQueryable<T> implementation and returns the matching entities:

    public class ActiveRegistrationsSpecification

    {

        public IQueryable<Registration> SatisfyingElementsFrom(

            IQueryable<Registration> registrations)

        {

            return registrations.Where(r => r.Status != AgreementStatus.Incomplete);

        }

    }

The beauty of this pattern is that you can easily verify its behavior by passing in an arbitrary in-memory collection and observing the resulting subset from a unit test. At run-time, the repository will simply pass an IQueryable<T> implementation that directly talks to LINQ-to-NHibernate.

I already blogged about the combination of NHibernate and WCF Data Services, so I will refrain from repeating myself. However, one thing to remember when working with Silverlight, is that it doesn't really work well with services that throw FaultExceptions. In fact, it does not even understand them and treat them like a generic error 500. Luckely, the MSDN library contains a great article that explains how to introduce a custom Endpoint Behavior to overcome this. For the lazy people among us, get the code from my CQRS example so that you tuck its extension element in your web.config like this:

<configuration>

  <system.serviceModel>

    <extensions>

      <behaviorExtensions>

        <add name="silverlightFaults"

             type="TheKitchen.Common.SilverlightFaultBehavior, TheKitchen.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>

      </behaviorExtensions>

    </extensions>

    <behaviors>

      <endpointBehaviors>

        <behavior name="">

          <silverlightFaults/>

        </behavior>

      </endpointBehaviors>

    </behaviors>

  </system.serviceModel>

</configuration>

Next time, I’ll deal a bit with the domain model.