In WCF Web API we have 2 extensibility points which seem very similar. They both are designed for very different reasons. Recently the question of which to use when popped up on our forums. Below is some guidance.
Message handlers (Currently DelegatingChannel but will be renamed to DelegatingHandler) only deal with http messages (hence the name), you can use them to modify the request or the response or to stop the request and immediately return a response. So in general you use message handlers for addressing http specific concerns, for example:
- Logging each request (logging the uri)
- Checking for if-match / if-non-match headers and returning a 304 (not modified)
- Embedding an ETag header in the response
- Setting accept headers based on the uri (I do this in the ContactManager)
- Checking for API keys as in Pablo's (@cibrax) Handler here, or handling other security concerns like OAuth. (Our OAuth integration in the future will sit here.)
A few things to note about message handlers
- They are configured per host not per operation
- They sit very low in the WCF stack in the channel layer making them ideal for security level concerns.
- They are arranged in a russian doll model meaning each handler calls to it's inner handler. This lets you do plug in pre-post handling before the handler is called.
- They only support async (Task<T>)
Opeation handlers (HttpOperationHandler) deal with taking the message and manufacturing the parameters for an operation or vice versa. It is the responsibility of the operation handler pipeline to ensure that for every parameter in the method there is a corresponding value it is also the responsibility of the pipeline to take any return/out values and modify the message appopriately with the correct representation. Those values can either be pulled from the message itself (such as parsing the uri into an object) or from custom logic like talking to a respository. The exception here is the value that represents the content of the message. It is the responsibility of the Formatters to handle taking the body and turning into an object or vice versa. Common use cases:
- Taking a portion of the URI and manufacturing an object. An example of this would be taking a uri like http://maps.com/location/100,00 and turning it into a Location object with latitude / longitude properties.
- Taking the content and compressing / decompressing it with gzip. Darrel Miller (@darrel_miller) has a nice example of this
- Logging specific parameters of an operation
- Validating the body, i.e. someone posts a customer in one of multiple formats. The formatter runs and turns it into a customer (based on conneg) and then the handler validates the model to see that the value are correct.
Here's the things to note about operation handlers.
- They are configured per operaiton not per host
- Manufacture values which are used by other handlers in the pipeline or by the operation
- They are arranged in a pipeline where each handler is called in succession but one handler does not call the other.
- They only support sync in the box
- They can stop the pipeline by throwing an HttpResponseException<T>
Which to use really depends on your scenarios. If you are trying to address pure http concerns use message handlers, if you are trying to address application level concerns that work with models etc, use operation handlers.