Decorator Pattern with WCF and Castle Windsor


How do you extend a WCF Service that you cannot modify? Or even if you can modify it, should you? Consider the Open Closed Principle. Assuming that you can’t modify the existing service, but want to leverage existing service somehow from your new service, what should we do? That’s where the Decorator Pattern comes into the picture.

The Decorator Pattern is commonly used to modify or add additional behaviour to a class dynamically without modifying it’s current behavior.

Assuming we have an existing service, like so.

public class ContosoService : IContosoService
{
    private static Employee[] employess = new Employee[] {
                new Employee { Id="D001", Name="Dave", Department="Accounts" },
                new Employee { Id="D002", Name="Chris", Department="IT" },
                new Employee { Id="C098", Name="Danny", Department="HR" },
                new Employee { Id="C099", Name="Susan", Department="Management" }
            };

    private ILogger _logger;

    public ILogger Logger
    {
        get { return _logger; }
        set { _logger = value; }
    }

    public Employee[] GetEmployees()
    {
        _logger.Log("Calling Contoso Service: GetEmployees operation");
        return employess;
    }

    public int GetLeaveBalance(string empId)
    {
        _logger.Log("Calling Contoso Service: GetLeaveBalanace operation");
        return 14;
    }

}

Suppose we need to create a new customized Service, where GetEmployees() with only return employees with Id starting with “D”, and GetLeaveBalance() with return an additional 7 days. First we will need to define a Decorator class that inherits from IContosoService.

public class ServiceDecorator : IContosoService
{
    private IContosoService _decoratedService;

    public ServiceDecorator(IContosoService service)
    {
        _decoratedService = service;
    }

    public virtual Employee[] GetEmployees()
    {
        return _decoratedService.GetEmployees();
    }

    public virtual int GetLeaveBalance(string empId)
    {
        return _decoratedService.GetLeaveBalance(empId);
    }

}

Now we are ready to decorate our new CustomContosoService, like so.

public class CustomContosoService : ServiceDecorator
{
    private ILogger _logger;

    public CustomContosoService(IContosoService service)
        : base(service)
    { }

    public ILogger Logger
    {
        get { return _logger; }
        set { _logger = value; }
    }

    public override Employee[] GetEmployees()
    {
        _logger.Log("Calling Custom Contoso Service: GetEmployees operation");
        return base.GetEmployees().Where(e => e.Id.StartsWith("D")).ToArray();
    }

    public override int GetLeaveBalance(string empId)
    {
        _logger.Log("Calling Custom Contoso Service: GetLeaveBalance operation");
        return base.GetLeaveBalance(empId) + 7;
    }
}

The problem with CustomContosoService is that WCF can only instantiate a parameterless constructor, but using the Decorator pattern, this becomes a problem. That’s where Castle Windsor‘s dependency injection comes to save the day. I’m a big fan of Dependency Injection and Inversion of Control for decoupling your application, and Windsor does a terrific job. If you want to learn more about this pattern, I recommend this great article .

Moving on, if you have noticed that there are ILogger properties on both the services, they are going to injected dynamically via a configuration file (“windsor.xml”) and we have the ability to inject any kind of concrete logger at runtime, e.g. a Console logger, Event Viewer logger…etc. Dependency injection provides us this flexibility without needing to change any dependencies or code.

Now let’s take a look at how we can incorporate Windsor into this implementation. First of all, I’m using WcfFacility from Windsor. It has not been released yet, so I’m using dlls from their trunk code for this example, build 1060. You can pick any working build, as long they are compatible with .NET 3.5. You need to reference the following Dlls:

  • Castle.Windsor
  • Castle.MicroKernel
  • Castle.Facilities.WcfIntegration

Then create an xml file called “Windsor.xml”, like so.

<configuration>
  <components>

    <component id="contosoService"
               service="DecoratorWCF.IContosoService, DecoratorWCF"
               type="DecoratorWCF.ContosoService, DecoratorWCF">
<parameters>
        <logger>${logger.console}</logger>
      </parameters>
    </component>

    <component id="customContosoService"
               service="DecoratorWCF.IContosoService, DecoratorWCF"
               type="DecoratorWCF.CustomContosoService, DecoratorWCF">
<parameters>
        <service>${contosoService}</service>
        <logger>${logger.console}</logger>
      </parameters>
    </component>

    <component id="logger.console"
              service="DecoratorWCF.ILogger, DecoratorWCF"
              type="DecoratorWCF.TraceLogger, DecoratorWCF">
    </component>

    <component id="metadata.behavior"
              service="System.ServiceModel.Description.IServiceBehavior, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
              type="System.ServiceModel.Description.ServiceMetadataBehavior, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<parameters>
        <httpgetenabled>true</httpgetenabled>
      </parameters>
    </component>

  </components>
</configuration>

If you are familiar with xml, this should be fairly understandable. Important thing here is the <parameter> tags and the ${component_id}, which defines what components to inject via properties and constructor parameters. Lastly, take note of the component with id = “metadata.behavior”, this defines the ServiceMetadataBehavior which will be automatically applied to all WCF services. Next let’s take a look at the web.config.

  <system .serviceModel>
  <services>
   <service name="contosoService">
    <endpoint address="" binding="wsHttpBinding" contract="DecoratorWCF.IContosoService">
     <identity>
      <dns value="localhost" />
     </identity>
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
   </service>
   <service name="customContosoService">
    <endpoint address="" binding="wsHttpBinding" contract="DecoratorWCF.IContosoService">
     <identity>
      <dns value="localhost" />
     </identity>
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
   </service>
  </services>
  </system>

In order for Windsor to work its magic, the service name has to match with the component id you are injecting. Lastly you need to modify the .svc file to use Windsor’s WCF factory class. Similarly the service name must match up to the component id name.

< %@ ServiceHost Language="C#" Debug="true" Service="customContosoService" Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration" %>

Lastly, in order for the windsor.xml to be picked up and “processed” by Windsor, we need to implement the following code, when the service first starts up. For example, if you are hosting WCF services in a Windows Service, you would need to wire up Windsor
at the OnStart event. For this example, we will be wiring it up at the Application_Start in Global.asax, like so.

public class Global : System.Web.HttpApplication
{
    private static IWindsorContainer container;

    protected void Application_Start(object sender, EventArgs e)
    {
        container = new WindsorContainer().AddFacility<wcffacility>().Install(Configuration.FromXmlFile("windsor.xml"));
    }

    protected void Application_End(object sender, EventArgs e)
    {
        container.Dispose();
    }

    protected void Session_Start(object sender, EventArgs e){ }

    protected void Application_BeginRequest(object sender, EventArgs e) { }

    protected void Application_AuthenticateRequest(object sender, EventArgs e) { }

    protected void Application_Error(object sender, EventArgs e) { }

    protected void Session_End(object sender, EventArgs e) {}
}

Good, we’re done. If you download the sample code and run it, you should see the following result in the console window and the trace logger output, where we are calling the CustomContosoService using a console application.

class Program
{
    static void Main(string[] args)
    {
        using (CustomContosoServiceClient.ContosoServiceClient customContosoClient = new CustomContosoServiceClient.ContosoServiceClient())
        {
            CustomContosoServiceClient.Employee[] employees = customContosoClient.GetEmployees();

            employees.ToList().ForEach(c => Console.WriteLine(string.Format("Id: {0}, Name: {1}, Department: {2}", c.Id, c.Name, c.Department)));

            int leaveBalance = customContosoClient.GetLeaveBalance("D001");

            Console.WriteLine(string.Format("Leave Balance: {0}", leaveBalance));

            Console.WriteLine("Press any key to end");

            Console.Read();

        }
    }
}

Test_console_output

WCF_Log

To summarize it all, we have seen the Decorator pattern put into use to add/modify behaviours and responsibilities to existing WCF services. Decorator becomes extremely useful in situations like these, and you can easily decorate more services if required painlessly and dependency-free using Windsor.

We have also seen how useful Dependency Injection and Inversion of Control is, especially when utilized with Decorator pattern and WCF. The beauty of utilizing these combination is that you can wrap any number of decorators around your existing service to extend it’s current behavior, without ever having to modify the existing service, or having your client (consumer) know about it. With a simple addition in the Windsor config file, the change happens transparently without having to tightly couple your code.

In my opinion, Windsor and WCF are a deadly duo, and I’m eagerly anticipating Windsor maturing even further with WCF integration.

Download this sample code here.

Share this post : del.icio.us it! digg it! dotnetkicks it! live it! reddit! technorati!

Advertisements

11 Responses to “Decorator Pattern with WCF and Castle Windsor”

  1. Tan Says:

    Great article!
    What about if i wanna add a new method to the CustomContosoService. Do i need to add the new method in the interface to ?

    • Ed Foh Says:

      thanks!

      yes you do need to add method to interface.

      • Tan Says:

        The service wont be so customizable. The decorator pattern only make so i can override existing methods. But i need to add my own methods to the customService and keep the base. Is there no way to this nicely. Because if i have to add the new method into the interface i can likely skip the the decorator there is no mean to it right ? or am i thinking it wrong ?

  2. Ed Foh Says:

    yes decorator is to override existing behavior. If you need to add new behavior to the custom service, you do not need to care about the decoration. You should not be adding the new method to the interface if it’s not a common behavior.

    You can create a new interface called ICustomContosoService, which inherits from IContosoService. You can add the new method onto ICustomContosoService so you get your new behavior and also preserve the old behavior. Hop that makes sense.

    • Tan Says:

      Now it makes more sense for me. Thanks for the help.
      Have a nice weekend.

      • Tan Says:

        Sorry one more thing. Then the CustomContosoService ahve to inherits from the interface, Like this.

        CustomContosoService : ServiceDecorator, ICustomContosoService

        correct ?

    • Tan Says:

      I tried that.
      But i cant get out my new methods that a added when doing service references im i doing it wrong?
      Because i only can get out methods from IContosoService not the ICustomContosoService.
      Thanks for the help

      • Ed Foh Says:

        in the WCF config, you need to change the contract property to “ICustomContosoService” in the endpoint so that WCF can pick up the new service interface, and generate the new methods. hope that helps.

      • Tan Says:

        Do you mean the windsor.xml file or the app.config wcf file.

      • Tan Says:

        Okay it was the windsor xml file. Thanks for the help now it works fine.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: