I just finished a huge WCF teaching tour. I was teaching every other week for several months. During that time I finally realized the best way to teach WCF extensibility.

But first some background. There are two types of extensibility in WCF – channel layer extensibility and service model extensibility. At the channel layer you are dealing explicitly with messages. There are only two reasons why you might want to write a channel:

  1. You need to create a new way of transporting the bits to the other process. For example you might want to create a file channel, that uses file sharing to move the bits across, or a UDP channel. BTW – you can find samples for doing both of those things, so don’t reinvent the wheel.
  2. You need a single outgoing message to result in more than one outgoing message. Most of the protocol channels fall into this category: security, transactions, reliable messaging, chunking, etc.

That’s it. There are no other valid reasons. The channel layer is more complicated than the service model layer, and more difficult to get right, so avoid it when you can.

With that out of the way, let’s focus on the other type of extensibility – service model extensibility. At this layer its hard to understand why it is so complicated. It all goes back to the WCF design goal – To be the single best way of getting any two pieces of software to communicate under any circumstances. In other words the WCF team has to support not only any known way of communicating, but any unknown way of communicating as well. Not just any way that exists now, but any way that might ever be invented. With a design goal like that you have to be REALLY flexible. And with flexibility comes the lesser liked ugly cousin – Complexity.

So the way extensibility at the service model layer works is like this. You have to author two classes. One is the actual functionality that you are trying to provide, and the other is used to plug that into the WCF plumbing (more about that later).

So for the first class what functionality can be extended? Well, there are so many hooks in WCF that it would be impossible to list them all, but some of the interfaces you might need to implement are listed here (courtesy of MSDN)

Interface Description
ICallContextInitializer Defines the methods that enable the initialization and recycling of thread-local storage with the thread that invokes user code.
IChannelInitializer Defines the interface to notify a service or client when a channel is created.
IClientMessageFormatter Defines methods that are used to control the conversion of messages into objects and objects into messages for client applications.
IClientMessageInspector Defines a message inspector object that can be added to the MessageInspectors collection to view or modify messages.
IClientOperationSelector Defines the contract for an operation selector.
IDispatchMessageFormatter Defines methods that deserialize request messages and serialize response messages in a service application.
IDispatchMessageInspector Defines the methods that enable custom inspection or modification of inbound and outbound application messages in service applications.
IDispatchOperationSelector Defines the contract that associates incoming messages with a local operation to customize service execution behavior.
IErrorHandler Allows an implementer to control the fault message returned to the caller and optionally perform custom error processing such as logging.
IInputSessionShutdown Defines the contract that must be implemented to shut down an input session.
IInstanceContextInitializer Defines the methods necessary to inspect or modify the creation of InstanceContext objects when required.
IInstanceContextProvider Implement to participate in the creation or choosing of a System.ServiceModel.InstanceContext object, especially to enable shared sessions.
IInstanceProvider Declares methods that provide a service object or recycle a service object for a Windows Communication Foundation (WCF) service.
IInteractiveChannelInitializer Defines the methods that enable a client application to display a user interface to collect identity information prior to creating the channel.
IOperationInvoker Declares methods that take an object and an array of parameters extracted from a message, invoke a method on that object with those parameters, and return the method’s return value and output parameters.
IParameterInspector Defines the contract implemented by custom parameter inspectors that enables inspection or modification of information prior to and subsequent to calls on either the client or the service.

Pasted from here

However, it is the second class is really the focus of this blog entry. This class is responsible for plugging the first class into WCF. You can extend WCF at three different levels, as shown in the diagram below. At the innermost level in red you can extend WCF for a single operation. You can also effect an entire endpoint (shown in purple), or even the entire service consisting of all endpoints.

Let me back up for just a second. The WCF service model extensibility is very similar to the extensibility model of you car. You open up the hood, then you can add parts, remove parts, change one part for another, but you have to know exactly what you are doing. Then you close the hood and use the newly altered engine to actually drive the car. So although it is not exactly easy, if you have seen a show like “Pimp My Ride”, you know there is nothing you can’t do. The same is true of WCF. WCF calls your behavior and it passes your behavior the “engine” at the place you trying to extend it. You alter the plumbing in any way you want, and then WCF uses the plumbing you have altered to actually run your service / endpoint / operation.

So if I am implementing an IServiceBehavior in the ApplyDispatchBehavior method I get a ServiceHostBase class which I can manipulate in any way I see fit. Actually I get two pieces of information. The first is the description of what should happen or the “manual”, and the second is the engine.

public interface IServiceBehavior
	void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase);
	// other members elided for clarity...

After the ApplyDispatchBehavior is called and my behavior has altered the ServiceHostBase, WCF uses the altered ServiceHostBase to “drive” my service.

Similarly for IEndpointBehavior in both the ApplyClientBehavior and the ApplyDispatchBehavior I get the WCF description and the plumbing for an endpoint.

public interface IEndpointBehavior
	void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime);
	void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher);
	// other members elided for clarity...

The same is true for an Operation.

public interface IOperationBehavior
	void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation);
	void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation);
	// other members elided for clarity...

The last part of the extensibility mechanism is how WCF actually finds out about the behavior that you wrote in step 2. This can be done in one of three ways: by applying an attribute, by programmatically adding the behavior (i.e. host.Description.Behaviors.Add) or by authoring a third class which inherits from BehaviorExtensionElement that describes what your behavior’s XML element can contain.

No comments yet.

No Comments »

You must be logged in to post a comment.