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.
In the last post about QueryStringConverter I mentioned that the way to replace the converter used by some operations in WCF WebHttp endpoints (they’re more widely known as WCF REST endpoints, although the purists may disagree with this name) is to create a class derived from WebHttpBehavior and override a virtual method from that base class. In this post I’ll go over the other virtual methods in that class, which makes extending WCF WebHttp endpoints (a little) easier than the general WCF endpoints.
Public implementations in WCF
The WebHttpBehavior class is concrete, so it can be used directly. There is one public subclass in WCF, WebScriptEnablingBehavior, which is the behavior used in endpoints compatible with the ASP.NET AJAX library--LINK. That behavior modifies the base with the following changes:
- Changes the DefaultBodyStyle property to WrappedRequest (and throws if one tries to set a different value)
- Changes the DefaultOutgoingRequestFormat and DefaultOutgoingResponseFormat to WebMessageFormat.Json (instead of Xml)
- Changes the properties AutomaticFormatSelectionEnabled, FaultExceptionEnabled and HelpEnabled to false (and throws if one tries to set them to true).
- Adds additional validation for features not supported by the ASP.NET AJAX library
- Changes the default QueryStringConverter to use the JsonQueryStringConverter, which allows the passing of complex types (encoded in JSON) in the query string for GET requests as well)
- Adds a new IErrorHandler in the server which changes exceptions in a JSON format understood by the ASP.NET AJAX library
- Adds a new IClientMessageInspector in the client, for the (not so common) case where this behavior is used at the client side so it will be able to understand the JSON format emitted by the error handler mentioned above
So that class changed a lot of the behavior. And the good thing is that all those changes were made via public virtual method, so it’s possible to recreate something similar with “normal” user code as well.
Those are the virtual members which can be overridden to change the behavior of the base type:
IEndpointBehavior methods: the class implements this interface, so those methods can also be overridden.
- AddBindingParameters: as usual, it’s unused in the base class, but can be overridden by derived types
- ApplyClientBehavior: Sets up the formatters for all operations and a message inspectors, by calling all the virtual methods which are client-specific listed below
- ApplyDispatchBehavior: Sets up formatters for all operations, defines an inspector used for JSONP requests (if enabled), sets up the operation selector which is UriTemplate-aware, and essentially calls all the virtual methods which are server-specific and listed below
- Validate: Applies some basic validation for the HTTP-ness of the endpoints, such as if it’s actually on an HTTP transport, among other things
Specific WebHttpBehavior properties: all the great virtual properties which are tailored to specific extensions and can be overridden by derived classes.
- AutomaticFormatSelectionEnabled (new in 4.0): defines whether automatic format selection for responses is enabled. Derived classes can force / disable it by overriding this property (default = false)
- DefaultBodyStyle: defines the body style for operations where they are not explicitly set by the BodyStyle property of [WebGet] or [WebInvoke] (default = Bare)
- DefaultOutgoingRequestFormat: used for client-side only, defines the format for outgoing requests (incoming requests can be of any supported format) if not explicitly set by the OutgoingRequestFormat property of [WebGet] or [WebInvoke] (default = Xml)
- DefaultOutgoingResponseFormat: used for server-side only, defines the format for outgoing responses (incoming responses can be of any supported format) if not explicitly set by the OutgoingResponseFormat property of [WebGet] or [WebInvoke] (default = Xml)
- FaultExceptionEnabled (new in 4.0): defines whether a SOAP-like fault is to be returned (with a 500 status code) if an exception (even WebFaultException which specifies a status code) is thrown by the service (default = false)
- HelpEnabled (new in 4.0): defines whether a help page is enabled for the endpoints using this behavior (default = false)
Specific WebHttpBehavior methods: same as the previous list, this time with methods instead of properties. All of those methods are protected (i.e., can be overridden, but not called directly unless calling the base implementation by the derived type)
- AddClientErrorInspector: the base class adds a client message inspector which throws exceptions for 500 HTTP responses
- AddServerErrorHandlers: the base class adds an error handler which know how to deal with WebFaultException. Also, if FaultExceptionEnabled is enabled, the handler will create the appropriate “web fault” for errors
- GetOperationSelector: the base class adds an instance of the WebHttpDispatchOperationSelector class, which knows how to select an operation based on UriTemplate matching
- GetQueryStringConverter: as shown in the post about QueryStringConverter, the base class returns an instance of the QueryStringConverter class, but derived types can override it to return a subclass which can deal with more types.
- GetReplyClientFormatter: allows derived classes to change the formatter used to convert the incoming responses into the operation outputs (return value and any out/ref parameters) in a per-operation basis
- GetReplyDispatchFormatter: allows derived classes to change the formatter used to package the operation outputs for outgoing responses into a Message object in a per-operation basis
- GetRequestClientFormatter: allows derived classes to change the formatter used to package the operation inputs for outgoing requests into a Message object in a per-operation basis
- GetRequestDispatchFormatter: allows derived classes to change the formatter used to convert the incoming requests into the operation input parameters in a per-operation basis
- ValidateBinding: allows derived classes to validate the binding only for compatibility. IMO this is another one of the extensibility points which weren’t absolutely necessary (derived classes could simply override Validate, but I’m sure there is some scenario where having this will save some lines of code)
Now, this class is fairly extensible, but it has a lot of room for improvement (which is coming in the new WCF Web APIs). The biggest problem is that some of the features, such as URI templates and the help page aren’t aware of the changes done in derived classes. And once you start overriding some of the methods (such as the request formatters, you actually have to implement the URI template yourself – we had to do that in the jQuery Support in the WCF Codeplex page, and it was a lot of work). Some derived classes (such as WebScriptEnablingBehavior simply disallow UriTemplates and the help pages to avoid dealing with this problem.
How to use a class derived from WebHttpBehavior
This is fairly trivial – you just derive from that class, and instead of adding a WebHttpBehavior to your endpoint, you add your own class.
Real world scenario: a JsonValue-aware behavior which supports both server and client side
The JsonValue type (and its derived classes) was originally introduced in Silverlight 2 and was a great way to deal with untyped JSON data – but it was limited to Silverlight. When we started the WCF Codeplex project, the first component we released (called “jQuery Support”, since it also added support for forms/url-encoded data, which is the default format for jQuery ajax calls) was a beefed up version of those classes, along with the integration with the WCF service model, by means of a new behavior (we called it WebHttpBehavior3, since WebHttpBehavior2 had been used in the REST Starter Kit – which by the way is deprecated, all of its features either made it to the framework or are being maintained at the WCF Codeplex site). The WebHttpBehavior3 class used many of the extensibility points of WebHttpBehavior to provide a server-side support for untyped JSON data.
But I’ve seen some people trying to do the same in the client side, so I decided to use this scenario as the sample for this post. To avoid problems with UriTemplates, I’ll limit the code to deal with either responses or simple GET requests without templates. Some of the code is “borrowed” from the Codeplex site, some of it is new (I simplified some of it a little to fit in this series format).
And before starting with the code, the usual disclaimer: this is a sample for illustrating the topic of this post, this is not production-ready code. I tested it for a few contracts and it worked, but I cannot guarantee that it will work for all scenarios (please let me know if you find a bug or something missing). A more complete implementation would also include UriTemplate support (or even better, it would be built on top of the new WCF Web APIs), it would have more error handling, and it may also include client-side support for GET operations with a single JsonValue parameter. It could also support complex objects in the query string (right now it only supports record-like data).
Let’s start with the services which I’ll use to test this. The first service implements two contracts, the first with one operation which returns a JsonValue (and takes an optional boolean parameter indicating whether the operation should throw), and the second takes a JsonValue argument which will be bound to the query string, and returns the JSON (as a Stream) back to the client. The second service doesn’t use JsonValue at all, but it will be used to validate that we can use a contract with JsonValue on the client side.
Now we can go to the behavior. First we’ll override the default outgoing formats from Xml to Json. Notice that we can’t simply set those values in the base class from the constructor, since those are virtual properties which shouldn’t be set while the object is being created.
Next we’ll just add a little more validation to the base type. Since our reply formatters can’t handle out / ref parameters, we want to have an error when the service / client is being opened (and not when a request is being made).
Now for the reply formatters. If the operation has a single parameter of type JsonValue (or its subclasses), and the request is not wrapped, we’ll use our own formatter (coming up later). Otherwise, we’ll just return the formatter from the base class.
This is a new “feature” on this sample (which doesn’t exist on Codeplex) which lets a [WebGet] operation have a single JsonValue (or JsonObject, since the query string is a key/value pair collection which maps well to a JsonObejct) parameter – and all of the query string will be bound to it.
Finally, we’ll add an error handler which knows how to deal with WebFaultException<T> exceptions where the detail type is a JsonValue type. This time we’ll use the same trick as we did on the Codeplex project (since the base type doesn’t return the error handlers it added), which is to let the base add first, then find which ones it did, then remove them and pass to our error handler implementation to delegate as necessary.
And the behavior class is done. Now let’s go to the classes which implement the extensions which we overrode. First is the request formatter for GET requests. It uses the HttpUtility class to parse the query string, and creates a simple JsonObject based on the query string values.
Now the reply formatter for the server side. The implementation is fairly simple, as it delegates creating the message to a body writer which is JsonValue-aware, and setting the appropriate message properties to have the response serialized as JSON.
The body writer is also simple, since it uses one of the methods defined in the JsonValueExtension class (from the Codeplex project) which knows how to write the JsonValue in a XmlWriter using the JSON to XML mapping rules.
Next is the client reply dispatcher. Again, using a function from the JsonValueExtensions class to handle the JSON to XML mapping, its implementation is quite trivial.
Finally the error handler, which is the biggest of the classes, although it’s also not that complex. On ProvideFault, if it turns out that the exception which caused the handler to be invoked is a WebFaultException<T>, where the T is a JsonValue type, then we create a JSON message with the detail as given in the exception, and the status code from there as well.
Now that everything is set up we can start testing the program. To test the server part I’ll use a HttpWebRequest-based client, and to test the client part we’ll talk to the service which doesn’t use JsonValue (the one with a single operation with no JsonValue in its signature).
And that’s it. Extending WebHttpBehavior is a little easier than the normal extensibility in WCF, but it still has some ways to go to become easier. Hopefully the WCF Web APIs will solve them to consolidate WCF as a top player in the services world for REST.