Service Locator Pattern with WCF and Unity

The Service Locator Pattern is no stranger to enterprise design patterns. In fact, you will see it quite frequently when working in corporate infrastructures. Some developers love it, others despise it. This post isn’t to debate the case for or against the Service Locator. It is, however, a practical example on how to leverage the pattern utilizing WCF & Unity.

Another design pattern post?!

I know I know…some of you will probably scoff at yet another developer rehashing the same design pattern (or anti-pattern depending on your camp) that is all over the internet. There is some true to this, however, this is going to be a small real world example on how to incorporate the pattern using Unity for a WCF service.

Unity Framework and IoC.

I will not be going over the basics of IoC, or the Unity Framework for that matter. If you need a crash course on how to use Unity, I would recommend looking over the NuGet package page and MSDN.

The Use Case

Suppose we need to build a service to process purchase orders for two of your clients (Let’s call them Foo and Bar). Simple right? Now lets suppose that along with your standard order processing logic, each client has it’s own unique ‘post processing’ logic that needs to be executed.

The Design

WCF Unity Service Locator Class Diagram

We will distinguish our clients based on an element within our message (I’ll call it Source). I can then use this message element to look up a particular implementation of our order processor based on the message source using Unity.

The Data Contract

For this example, we will use a basic message class for holding data related to the order. This class will also contain two common message elements, the header and response. You could (and should) encapsulate this into a base message class, but we will keep things simple for this example.

[DataContract]
public class OrderMessage
{
    [DataMember]
    public MessageHeader Header { get; set; }

    [DataMember]
    public MessageResponse Response { get; set; }

    [DataMember]
    public string Source { get; set; }

    [DataMember]
    public int ProductID { get; set; }

    [DataMember]
    public int Quantity { get; set; }

    [DataMember]
    public string OrderID { get; set; }

    [DataMember]
    public int OrderTotal { get; set; }
}

[DataContract]
public class MessageHeader
{
    [DataMember]
    public string Source { get; set; }

    [DataMember]
    public string Auth { get; set; }

}

[DataContract]
public class MessageResponse
{
    [DataMember]
    public int ResponseCode { get; set; }

    [DataMember]
    public string ResponseMessage { get; set; }
}

The Code

Lets first look at the Service Contract for our new OrderService. This will retrieve the implementation instance of IOrderProcessor based on the OrderMessage Source element from the message.

[ServiceContract]
public interface IOrderService
{
    [OperationContract]
    OrderMessage ProcessOrder(OrderMessage message);
}

public class OrderService : IOrderService
{
    private WcfServiceLocator _serviceLocator;
    private IUnityContainer _container;        

    public OrderService()
    {
        UnityConfigurationSection section = 
            (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
        _container = new UnityContainer();
        section.Configure(_container);
        _serviceLocator = new WcfServiceLocator(_container);     
    }

    public Core.Model.OrderMessage ProcessOrder(Core.Model.OrderMessage message)
    {
        var _processor = _serviceLocator.GetInstance<IOrderProcessor>(message.Header.Source);
        return _processor.ProcessOrder(message);
    }
}

GOTCHA!

One thing to watch out for with leveraging Unity in this type of design is it will throw an ActivationException if it cannot find a valid implementation of the interface you’re looking for.

So in this example, if we were to send a message for Source ‘FooBar’, we would throw an exception since Unity could not find this mapping based on that name. You can either catch the exception and ignore, or define a default processor to use when this occurs.

IOrderProcessor & BaseOrderProcessor

We need to create a generic interface and base processor in order to process the common logic between clients. We will use the BaseOrderProcessor to retrieve the order totals for both the Foo & Bar client processors.

public interface IOrderProcessor
{
    OrderMessage ProcessOrder(OrderMessage message);        
}

public abstract class BaseOrderProcessor : IOrderProcessor
{
    public virtual OrderMessage ProcessOrder(OrderMessage message)
    {
        message.OrderTotal = GetOrderTotal(message.ProductID, message.Quantity);
        return message;       
    }

    protected int GetOrderTotal(int ProductId, int Quantity)
    {
        int UnitPrice = GetPriceByProductId(ProductId);

        if (UnitPrice > 0)
            return UnitPrice * Quantity;

        return -1;
    }

    protected int GetPriceByProductId(int ProductId)
    {
        //example. Should look up in a database or somewhere
        int lookupPrice = -1;            

        switch (ProductId)
        {
            case 100:
                lookupPrice = 8;
                break;
            case 115:
                lookupPrice = 15;
                break;               
        }

        return lookupPrice;
    }
}

FooOrderProcessor & BarOrderProcessor

I’ve implemented both client processors with similar logic. Both will use their parent’s ProcessOrder method to calculate the total for the order.

public class FooOrderProcessor : BaseOrderProcessor
{        

    public override OrderMessage ProcessOrder(OrderMessage message)            
    {
        OrderMessage responseMessage = new OrderMessage();
        responseMessage = base.ProcessOrder(message);

        string OrderID = Guid.NewGuid().ToString("N");
        message.OrderID = OrderID;

        responseMessage.Response = new MessageResponse
        {
            ResponseCode = 200,
            ResponseMessage = String.Format("Order Processed for Company Foo Successfully")
        };

        return responseMessage;
    }
}

public class BarOrderProcessor : BaseOrderProcessor
{
    public override OrderMessage ProcessOrder(OrderMessage message)
    {
        OrderMessage responseMessage = new OrderMessage();
        responseMessage = base.ProcessOrder(message);

        responseMessage.Response = new MessageResponse()
        {
            ResponseCode = 210,
            ResponseMessage = String.Format("Order Processed for Company Bar Successfully")
        };

        return responseMessage;
    }
}

Wiring up the Unity configuration

The web.config of your WCF service will need to include the Unity mapping declarations for each order processor. Notice that each mapping uses the client name to distinguish the instance.

<unity>
<containers>
  <container>
    <types>          
      <type type="WcfUnityServiceLocator.Core.Processor.IOrderProcessor, WcfUnityServiceLocator.Core" mapTo="WcfUnityServiceLocator.Core.Processor.FooOrderProcessor, WcfUnityServiceLocator.Core" name="Foo"/>
      <type type="WcfUnityServiceLocator.Core.Processor.IOrderProcessor, WcfUnityServiceLocator.Core" mapTo="WcfUnityServiceLocator.Core.Processor.BarOrderProcessor, WcfUnityServiceLocator.Core" name="Bar"/>
    </types>
  </container>
</containers></unity>

Test Drive

Stand up a local debug session of your new WCF service and fire up soapUI and add your local service WSDL. Once you’ve done that you should be able to send two messages, one with a source of Foo and another with a source of Bar.

Testing Foo Source

WCF Unity Service Locator Test Foo

Test for Bar Source

WCF Unity Service Locator Test Bar

Pattern Advantages

The biggest advantage using this pattern is once you have the base process flow implemented, the only time you’ll need to incorporate new a new order processor is when a new client needs additional processing aside from your normal processing. If we had implemented these as two different endpoints, say as ProcessFooOrder & ProcessBarOrder, we would have to stand up new endpoints each time I would need additional processing for a client.

Wrap up

If you’re making exceptions to your normal process flow within a service to satisfy a client need, then I would highly recommend consider leveraging this design to decouple your processing into manageable parts.

One thought on “Service Locator Pattern with WCF and Unity

  1. Tim Schwallie

    a few easy questions:
    Where did WcfServiceLocator come from?
    What instancing will this support?
    Does each service contract hosted on a site need this set up?

Comments are closed.