Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Windsor WCF Integration

DZone's Guide to

Windsor WCF Integration

·
Free Resource

I've been playing with the Windsor WCF Integration facility today. I've been using a recent trunk build of the Castle project, and since there's been a lot of work recently on the WCF facility, the docs on the Castle site are somewhat out of date. I had to work out how to use the facility by reading the unit tests and a post by Craig Neuwirt to the Castle Project Development list.

So why would you want to integrate WCF with your IoC container? When you use an IoC container in your application it should be the repository of any service that you consume. The service consumer should not care about how the service is implemented or where it comes from. A service should also not be concerned about how it is consumed. The Windsor WCF facility allows you to use your WCF services and proxies as if they were any other service provided by the container.

Let's think about how this might help us when writing enterprise applications. My eCommerce platform, Suteki Shop, sends the customer an email confirming that they've made an order. It sends them another email when the order is dispatched. I have an interface IEmailSender that defines the contract for sending an email. Currently my Windsor configuration maps the IEmailSender service to a class called EmailSender. The OrderController expects to be given an instance of IEmailSender in its constructor. So now it gets an actual instance of EmailSender that wraps the .NET API for sending emails. When the customer clicks the 'order' button the request blocks while an email is sent. This isn't a very scalable solution, but I'm not worried about it now because the only client I have for Suteki Shop is low volume. If their shop take off and starts to get a lot more traffic, I will want to have a more scalable architecture for sending emails. With the WCF integration I could configure IEmailSender to provide a WCF proxy instead of a concrete class. I could then install EmailSender (the IEmailSender implementation) on another server and configure the local container to expose it as a WCF service. The protocol I use can be configured using WCF. So I could use TCP, SOAP, MSMQ, or whatever fitted the purpose. The key point is that by using the WCF facility I've been able to take a part of my application and move to to a new process or machine without touching a single line of code.

So how do you use the WCF facility?

Service

Let's assume we have a simple service interface:

[ServiceContract(Namespace = "Mike.WindsorWCFIntegration")]
public interface ICustomerService
{
[OperationContract]
Customer GetCustomer(int id);
}

Customer is just some entity in my application. In order to serve this via WCF we have to attribute the service interface with WCF attributes: ServiceContract and OperationContract. We don't have to do anything to the existing Windsor.config file, it looks the same as before:

<component id="customerService"
service="Mike.WindsorWCFIntegration.ICustomerService, Mike.WindsorWCFIntegration"
type="Mike.WindsorWCFIntegration.DefaultCustomerService, Mike.WindsorWCFIntegration">
</component>

We're telling the container that when a component asks for an ICustomerService (or 'customerService' by name) they will be given DefaultCustomerService. Since I'm going to host the service as part of a web application, we can use the WCF IIS integration and create a CustomerService.svc file for the customer service that defines the service host:

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

Note that the Service attribute specifies the same name as the component id in the Windsor.config. The other important point is that we're asking WCF to use the Castle DefaultServiceFactory. This service factory wraps the Windsor container which it uses to resolve any service requests.

We configure WCF as normal:

<system.serviceModel>
<services>
<service name="customerService">
<endpoint contract="Mike.WindsorWCFIntegration.ICustomerService" binding="basicHttpBinding" />
</service>
</services>
</system.serviceModel>

Finally we have to register the WCF Facility with the container on application start:

protected void Application_Start(object sender, EventArgs e)
{
Container = new WindsorContainer()
.AddFacility<WcfFacility>()
.Install(Configuration.FromXmlFile("Windsor.config"));
}

The nice thing is that we haven't had to alter our Windsor.configuration or our existing service. Although we did have to attribute our service interface with WCF specific concerns which is a bit of a shame.

Client

The client side story is also pretty simple. Here's a client service that uses the customerService:

using System;

namespace Mike.WindsorWCFIntegration.Client
{
public class DoSomethingWithCustomers : IDoSomethingWithCustomers
{
private readonly ICustomerService customerService;

public DoSomethingWithCustomers(ICustomerService customerService)
{
this.customerService = customerService;
}

public void DoIt()
{
WriteClientDetails(customerService);
WriteClientDetails(customerService);
}

private static void WriteClientDetails(ICustomerService customerService)
{
var customer = customerService.GetCustomer(24);
...
}
}
}

It's expecting the customerService to be injected by the container. The Windsor.config has to specify that ICustomerService is provided by WCF:

<component id="customerService"
type="Mike.WindsorWCFIntegration.ICustomerService, Mike.WindsorWCFIntegration"
wcfEndpointConfiguration="customerClient">
</component>

The wcfEndpointConfiguration references the WCF configuration in App.config, note that it's the same as the endpoint name, 'customerClient':

<configuration>
<system.serviceModel>
<client>
<endpoint address="http://localhost:2730/CustomerService.svc"
binding="basicHttpBinding"
contract="Mike.WindsorWCFIntegration.ICustomerService"
name="customerClient">
</endpoint>
</client>
</system.serviceModel>
</configuration>

Once again we have to make sure that the WCF Facility is registered with the container (you can do this in the XML configuration as well):

var container = new WindsorContainer()
.AddFacility<WcfFacility>()
.Install(Configuration.FromXmlFile("Windsor.config"));

I hope I've been able to show that using WCF integration with Windsor can be a big win in extending component oriented application design to include serving and consuming remote services. Note that in none of the code above did I have to change the implementation of any of my services in order to make them work with WCF. You can retain your Dependency Injected, testable components and simply have them served onto the web. WCF allows you to configure the wire format (SOAP, REST, POX, binary) and transport (HTTP, named pipes, TCP-IP) independently of your component design. It's very easy to use and very nifty.

You can download the complete demo solution here.

Topics:

Published at DZone with permission of Mike Hadlow, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}