This post is part of a series about WCF extensibility points. For a list of all previous posts and planned future ones, go to the index page.
The first part of this series will focus on the behaviors. There are four kinds of behaviors, depending on the scope to which they apply: service, endpoint, contract and operation behaviors. The behavior interfaces are the main entry points for almost all the other extensibility points in WCF – it’s via the Apply[Client/Dispatch]Behavior method in the behavior interfaces where a user can get a reference to most of them.
Description vs. Runtime
The WCF behaviors are part of a service (or endpoint / contract / operation) description – as opposed to the service runtime. The description of a service are all the objects that, well, describe what the service will be when it starts running – which happens when the host for the service is opened (e.g., in a self-hosted service, when the program calls ServiceHost.Open). When the service host instance is created, and endpoints are being added, no listeners (TCP sockets, HTTP listeners) have been started, and the program can modify the service description to define how it will behave once it’s running. That’s because, during the service setup, there are cases where the service is in an invalid state (for example, right after the ServiceHost instance is created, no endpoints are defined), so it doesn’t make sense for the host to be started at that point.
When Open is called on the host (or, in the case of an IIS/WAS-hosted service, when the first message arrives to activate the service), it initializes all the appropriate listeners, dispatchers, filters, channels, hooks, etc. that will cause an incoming message to be directed to the appropriate operation. Most of the extensibility points in WCF are actually part of the service runtime, and since the runtime is not initialized until the host is opened, the user needs a callback to notify it that the runtime is ready, and the hooks can be used.
Behaviors
The WCF behaviors are defined by four interfaces (on the System.ServiceModel.Description namespace): IServiceBehavior, IEndpointBehavior, IContractBehavior and IOperationBehavior. They all share the same pattern:
public interface I[Service/Endpoint/Contract/Operation]Behavior {
void Validate(DescriptionObject);
void AddBindingParameters(DescriptionObject, BindingParameterCollection);
void ApplyDispatchBehavior(DescriptionObject, RuntimeObject);
void ApplyClientBehavior(DescriptionObject, RuntimeObject); // not on IServiceBehavior
}
The order in which the methods of the interfaces are called is the following:
- Validate: This gives the behavior an opportunity to prevent the host (or the client) from opening (by throwing an exception) if the validation logic finds something in the service / endpoint / contract / operation description which it deems invalid.
- AddBindingParameters: This gives the behavior an opportunity to add parameters to the BindingParameterCollection, which is used by the binding elements when they’re creating the listeners / factories at runtime. Useful to add correlation objects between behaviors and bindings. For service behaviors, this is actually called once per endpoint, since the BindingParameterCollection is used when creating the listeners for each endpoint.
- Apply[Client/Dispatch]Behavior: This is where we can get reference to the runtime objects, and modify them. This is the most used of the behavior methods (in most cases the other two methods are left blank). On the posts about each specific behavior I’ll have examples of them being used in real scenarios.
Read more: The .NET Endpoint