WCF services and shared assemblies

I often see situations on projects where they have design challenges with multiple webservices who share the same datacontracts (DTO). I already wrote a post about the separation of the service contract and the DTO’s, but i would like to extend that post with my vision on how we should work with mutiple services build on top of the same DTO’s.

To illustrate this I have build two WCF services which both have a reference to the DTO project called MyDataContracts. The solution for my services looks like this:

ServiceImplementation

Project 1 & 3 are service contracts and service implementations and project 2 contains the shared DTO’s.

The service contracts are very simple

[ServiceContract]
public interface ICustomerService
{
    [OperationContract]
    Customer GetCustomer(int value);
}
[ServiceContract]
public interface IInvoiceService
{
    [OperationContract]
    Invoice GetInvoice(int invoiceId);
}

The invoice DTO is implemented below

[DataContract]
public class Invoice
{
    int invoiceId = 0;
    Customer client;

    [DataMember]
    public int InvoiceId
    {
        get { return invoiceId; }
        set { invoiceId = value; }
    }

    [DataMember]
    public Customer Customer
    {
        get { return client; }
        set { client = value; }
    }
}

Because the invoice DTO has a datamember of the type customer the clients who want to interact with the invoice service have to know how a customer DTO will look like.

So that’s it for the service side. Now we take a look at the client side. When I consume services I usually create a service agent project which will be responsible for handling the calls to the services. This way I only have to implement exception handling once for the communication with my services. So my service agent project has two service references (two proxies). These two proxies will receive there own version of the customer DTO when I generate the proxy in the standard way. As you can see in the object browser below, both proxies have a Customer DTO generated. This can give you some annoying issues especially when you have to map values to your customer DTO and you have to pick a different one depending on the service you are communicating with.

ObjectBrowser

My client solution looks like this

ClientApplication

The first project is just a console application which interacts with my second project the service agent. I have created a service agent class.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MyServiceAgents.CustomerProxy;
using MyServiceAgents.InvoiceProxy;
using System.ServiceModel;

namespace MyServiceAgents
{
    public class ServiceAgent
    {
        public Customer GetCustomer()
        {
            CustomerServiceClient proxy = new CustomerServiceClient();

            try
            {
                return proxy.GetCustomer(1);
            }
            catch (FaultException ex)
            {
                // catch any faultexception from the service
            }
            catch (CommunicationException cex)
            {
                // ...
            }
        }

        public Invoice GetInvoice()
        {
            InvoiceServiceClient proxy = new InvoiceServiceClient();

            try
            {
                return proxy.GetInvoice(1);
            }
            catch (FaultException ex)
            {
                // catch any faultexception from the service
                throw new Exception();
            }
            catch (CommunicationException cex)
            {
                // ...
            }
        }
    }
}

The service agent has two methods. Each method is responsible to communicate with one of the two services. To make sure my proxy classes are available i have to add the following using statements

  • using MyServiceAgent.CustomerProxy
  • using MyServiceAgent.InvoiceProxy
    Adding these using statements will give us the problem of ambiguous classes.

Ambiguous

Well take a look at what happened right now. On the right side we see the customer & invoice service. The service project references the contracts project which contain two DTO’s. On the left side I have the service agent project which contains two service references. Adding these service references added a proxy for both services and DTO’s which are needed for the communication. The customer DTO is created twice.

Overview1

To resolve this issue you could use a shared assembly for the DTO’s. You have to make sure that when the service reference is added on the client project it doesn’t generate any DTO’s anymore. To make this possible you have to share your DTO assembly with your consumers, which looks fine to me. This will give you the following situation.

Overview2

I hope that sharing an assembly doesn’t need any explanation. To make sure that adding a service reference doesn’t generate any DTO’s you only have to add a reference from your service agent project to the DTO assembly. This way Visual Studio knows how to handle the generation of your service reference. To be sure click on the advanced button when you add a service reference.

VisualStudioSetting

Make sure the checkbox ‘Reuse types in referenced assemblies’ is enabled and you are good.

This solution can be related the the following SOA pattern: Canonical schema The DTO’s are set as standard across service contracts within an inventory boundary.

Regards,

Dennis

Advertisements