LINQ + WCF + Silverlight (Part Five)


Share

We’re ready to create the WCF services layer to implement our custom repositories and move data from the Silverlight client back to the server. The first problem we encounter is that WCF service implementations must be non-generic. In other words, the following service is illegal and will result in a runtime exception:

 
[ServiceContract]
public interface IRepositoryService<T> : IRepository<T>
{
    [OperationContract]
    T Update(T entity);
 
    // Details elided
}

Code Listing – An example of a WCF contract that will throw an exception because it is generic

If this design were possible, we’d have no problem writing services imitated our data layer repository services. So we set off to create a non-generic service contract to implement our repositories.

[ServiceContract]
public interface IRepositoryServices : IRepository<Customer>, IRepository<Product>
{
    [OperationContract]
    Customer Update(Customer entity);
 
    [OperationContract]
    Product Update(Product entity);
 
    // Details elided
}

Code Listing – An example of a non-generic WCF contract that will throw an exception because operation names are not unique

This contract looks better: it’s not generic and we’re providing contracts for each typed repository we want to utilize. Unfortunately this is still incorrect, because WCF method names must be unique. The Update method on the Customer and the Update method on the Product are necessarily non-unique names because they implement the IRepository<T> interface, so we’ve hit another roadblock here.

What option do we have? We could create concrete services for each and every IDataTransferObject defined in our specific model, but that would defeat the purpose of spending our time thinking about reusability and allowing reuse of our basic pattern in multiple applications. To solve this problem, we’re going to adapt an approach introduced by Ayende Rahien in his detailed screencast “Hibernating Rhinos 8“.

Our new service is a single method. It receives a message or collection of messages, processes it in a generic way, and then returns a response. This is a departure from Juval Lowy’s recommendations in “Programming WCF Services”, but it fits what we’re trying to accomplish in this case, and makes it very easy to extend a service in the future.

_Messages 
Diagram – Messages

Our basic structure is as generic as it gets. We’re defining an empty interface for a message, and creating abstract classes for the message, requests, and responses that implement it. We also define a message collection that contains an array of multiple messages, and a generic Get method that allows us to use the collection class to retrieve any type of request or response, but in a way that ensures we’re dealing with that specific type.

Using this multi-purpose abstraction, we can define a WCF service with a single operation.

[ServiceContract]
public interface IMessageBus
{
    [OperationContract]
    MessageCollection Process(MessageCollection messages);
}

Now our services are defined in the core assembly we can reuse, and we’re left to create the request/response messages that will perform the heavy lifting in our application. There are multiple ways to approach this depending on your tastes. For example, we could simply create requests and responses for every repository method as described earlier, and be no further long for using this architecture. Here is a simple example for a request/response designed to obtain Customer data.

[DataContract]
public class GetCustomerInfoRequest : RequestBase
{
    [DataMember]
    public int CustomerId { get; set; }
}
 
[DataContract]
public class GetCustomerInfoResponse : ResponseBase
{
    [DataMember]
    public Customer Customer { get; set; }
}

Code Listing – GetCustomerInfoRequest.cs / GetCustomerInfoResponse.cs

There doesn’t seem to be much happening here. We’re providing a request with the Customer’s identifier, and returning a response with the Customer data object. How did we do the work of retrieving the Customer with such a generic strategy? The missing piece is message handlers, which are classes that accompany your request and response classes to perform the work behind the scenes. We’ll cover those in the next post.

Article roadmap: LINQ + WCF + Silverlight
Download: Full solution

Kick It on DotNetKicks.com
blog comments powered by Disqus