Wednesday, March 18, 2009

Continuing my lovefest with the Windsor WCF facility, today I'm going to show you how to add behaviours to your WCF service. Behaviours are the core extension point for WCF and allow you to do pretty much anything with your service. Here's a nice brief description by Mehran Nikoo (it was the first thing that popped up on google :)

The WCF Facility automatically discovers any registered WCF behaviours and adds them to the service. The really nice thing about this is that because the behaviours are also IoC hosted components, the container can automatically provide their dependencies just like any other component. If you need to use any of your services inside the behaviour, simply inject it through the constructor as normal.

Let's look at an example where we want to log the entry and exit from an operation. Here's a simple service:

[ServiceContract]

publicinterface IHelloService

{

[OperationContract]

string Hello(string name);

}

publicclass HelloService : IHelloService

{

privatereadonly ILogger logger;

public HelloService(ILogger logger)

{

this.logger = logger;

}

publicstring Hello(string name)

{

logger.WriteLine("In Hello()");

returnstring.Format("Hello {0}", name);

}

}

It has a single operation 'Hello' that takes a name and returns 'Hello <name>'. It also has a dependency on ILogger which it uses to log that the Hello operation has been invoked.

Now lets create a WCF behaviour:

publicclass TestEndpointBehaviour : IEndpointBehavior

{

privatereadonly TestCallContextInitializer callContextInitializer;

public TestEndpointBehaviour(TestCallContextInitializer callContextInitializer)

We want to write to the logger before and after every operation invocation, to do that we're creating an Endpoint behaviour. The Endpoint behaviour gives you an opportunity, the ApplyDispatchBehaviour method, to add a 'CallContextInitializer' that can intercept operation invocations. Note that we resolve our CallContextInitializer from the IoC container by expecting it to be injected via a constructor parameter.

As an aside, I can't help feeling that the WCF behaviour API is overly complex, it hardly invites you in :) There's no way I would have worked out how to do this without looking at the documentation. Not at all the pit of success.

The ICallContextInitializer interface has two methods: BeforeInvoke and AfterInvoke where which allow us to execute any actions before and after the operation is invoked. Here we're just using the logger to write some interesting stuff out. Note that because the TestCallContextInitializer is also an IoC component we can resolve any of our services as constructor arguments again. Here we using the same ILogger service that our HelloService uses.

We first register the WcfFacility as usual. Then we register our components. Note that we don't need to do any special configuration for our EndpointBehaviour, the WCF Facility takes care of this for us.

When we run the test we get this output to the console:

Before Invoke
In Hello()
After Invoke
Hello Mike

As expected our behaviour was installed and invoked.

Integrating WCF and Windsor like this provides a very slick way of doing web services. I'm very impressed with Craig Neuwirt's work, what a star. Shame he doesn't blog more about it.

Code Rant

Notepad, thoughts out loud, learning in public, misunderstandings, mistakes. undiluted opinions. I'm Mike Hadlow, an itinerant developer. I live (and try to work in) Brighton on the south coast of England. Please don't mistake me for an expert in anything. I love technology and programming, but make no claims to be any good at it. Much of what you read here may be poorly thought out, wrong, or just plain dangerous.