WCF Extensibility part 5: Make your endpoints behave
In the previous post we looked at an operation behavior that applied the operation formatter to a particular operation description. Because this is default behavior for all operations in the interface defined, we will make life a little easier on us to have the operation behaviors applied automatically. A WCF endpoint consists of address, binding and contract. The latter is represented by the [ServiceContract] annotated interface, in our case IRcon and the target of our exercise.
The extensibility point that the WCF runtime provides is an endpoint behavior. Endpoint behaviors allow you to manipulate an endpoint’s definition. To create an endpoint behavior you need to implement the System.ServiceModel.Description.IEndpointBehavior interface:
public interface IEndpointBehavior
void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters);
void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime);
void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher);
void Validate(ServiceEndpoint endpoint);
This should look pretty familiar to you if you have read the previous part in this series. Again, you can apply your behavior both on the client and service side. There’s another validation moment in the Validate method and you can add binding parameters to the binding context for later use.
The implementation of ApplyClientBehavior is the most interesting one. Here we will apply the operation behavior to each of the endpoint’s operations.
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
if (endpoint.Binding is SourceRconTcpBinding)
foreach (OperationDescription description in endpoint.Contract.Operations)
private void ApplyFormatterBehavior(OperationDescription operationDescription, ServiceEndpoint endpoint)
if (operationDescription.Behaviors.Find<SourceRconOperationFormatterBehavior>() == null)
SourceRconOperationFormatterBehavior formatterBehavior = new SourceRconOperationFormatterBehavior();
Inside the implementation a simple loop over the operation descriptions in the contract is enough to get things going. The helper method ApplyFormatterBehavior makes sure that the SourceRconOperationFormatterBehavior behavior is applied only once.
An endpoint behavior needs to be added to the Behaviors collection of an endpoint to make it do its work. Given the client-side interface definition IRconProxy (which derives from both IRcon and IClientChannel) you can create a channel factory. The factory holds the the definition of the endpoint, provided by the implicit ABC in line 1 (address and binding are obvious, the generic <T> of the ChannelFactory represents the contract).
ChannelFactory<IRconProxy> factory = new ChannelFactory<IRconProxy>(binding, new EndpointAddress(uri));
Line 2 adds the behavior to the Behaviors collection of the endpoint. When the factory opens, the behavior gets applied. The operation formatters get applied at that moment as well. The operation formatters are used when the actual calls through the channel are made.
Side note: if you were to use a ClientBase<T> derived proxy, you would need to drill down into the proxy.ChannelFactory.Endpoint.Behaviors to get at the Behaviors collection, or use the proxy.Endpoint property for easier access.
To summarize, an endpoint behavior allows you to manipulate your endpoint. Behaviors are an opt-in, so it is your choice whether to apply them or not.