WCF Web API–Operation Handlers

This is the eleventh post on a series about the Preview 4 of WCF Web API. The sixth post, entitled WCF Web API–Processing Architecture, presented Web API’s runtime architecture, introducing several key architectural elements, namely message handlers and operation handlers. The last post described message handlers in more detail. In this post, the focus goes to operation handlers.

Operation handlers

Operation handlers are a WCF Web API extensibility point located after an operation is selected by the dispatcher, but before the operation’s method is called, as shown in the following diagram.

Pipelines

There is only one message handler pipeline, where each handler can execute before and after the operation’s invocation. However, there are two operation handler pipelines. The first, called the request pipeline, is composed by the operation handlers executed before the operation’s invocation. The second, called the response pipeline, is constituted by the operation handlers executed after the operation’s call. This characteristic is also visible in the above diagram.

Request pipeline

As described in the first post of this series, each operation has a set of input parameters, such as the request’s HttpRequestMessage, URI template variables and others. In the description model, these parameters are represented by the HttpParameter class (see this post for more information)

The main role of the request pipeline, located between the operation dispatcher and the operation’s method call, is to provide all the parameters required for this invocation. Despite the name similarity, there are significant differences between operation handlers and message handlers:

  • A message handler receives a HttpRequestMessage. An operation handler receives a set of HttpParameters, dynamically defined at startup.
  • A message handler asynchronously produces an HttpResponseMessage, by returning a Task<HttpResponseMessage>, which is typically completed after the operation was invoked. A request operation handler synchronously returns a set of HttpParameterbefore the operation is invoked. This HttpParameter set is also dynamically defined at startup.
  • A message handler can completely ignore the inner message handler, short-circuiting the operation’s invocation, and producing an HttpResponseMessage directly. The only way for an operation handler to short-circuit the call to the operation is by throwing an exception.

Defining operation handlers

An operation handler is defined by a class derived from HttpOperationHandler, as shown in the following code excerpt

class LoggingOperationHandler : HttpOperationHandler
{
    protected override IEnumerable<HttpParameter> OnGetInputParameters()
    {
		...
    }

    protected override IEnumerable<HttpParameter> OnGetOutputParameters()
    {
		...
    }

    protected override object[] OnHandle(object[] input)
    {
		...
    }
}

The OnGetInputParameters method returns a sequence of HttpParameter, defining the parameters that must be provided to the handler, i.e., the parameter names and types.

The OnGetOutputParameters method returns a sequence of HttpParameter, defining the parameters that are provided by the handler.

The above two methods are called only once, at startup. The third method, OnHandle, is called per request. It receives the input parameter values, declared by OnGetInputParameters, and returns the output parameter values, declared by OnGetOutputParameters.

Since the operation handler’s contract is dynamically defined by the two first methods, and not defined at compile time, the input and output type is object. However, WCF Web API contains a set of generic classes, such as HttpOperationHandler<T, TOutput>, where the input and output types are statically defined and the OnGetXxxxParameters methods are already implemented.

GenericHttpOperationHandler

Built-in operation handlers

WCF Web API uses the operation handler extensibility point to provide the parameters typically used by an operation. This is done by a set of built-in operation handlers, namely:

Example: tracing the parameter values

The following code excerpt shows a demo operation handler that inserts all the input parameters into the trace output.

class LoggingOperationHandler : HttpOperationHandler
{
    private readonly HttpParameter[] _prms;
    public LoggingOperationHandler(HttpOperationDescription desc)
    {
        _prms = desc.InputParameters.ToArray();
    }

    protected override IEnumerable<HttpParameter> OnGetInputParameters()
    {
        return _prms;
    }

    protected override IEnumerable<HttpParameter> OnGetOutputParameters()
    {
        yield break;
    }

    protected override object[] OnHandle(object[] input)
    {
        TraceInputs(input);
        return new object[0];
    }

    private void TraceInputs(object[] input)
    {
        var sb = new StringBuilder("# begin inputs trace #\n");
        for (int i = 0; i < _prms.Length; ++i)
        {
            sb.AppendFormat("  {0} : {1}\n", _prms[i].Name, input[i]);
        }
        sb.AppendLine("\n# end inputs trace #");
        Trace.Write(sb.ToString());
    }
}

Notice the following:

  • This handler receives exactly the same parameters as the operation’s method. This is accomplished by using the HttpOperationDescription to  obtain this information and return it on the OnGetInputParameters.
  • This handler has no output parameters.
  • The OnHandle method receives the operation’s input parameter values and writes them into the trace output.
  • Since the input parameter collection is not known in compile time, this operation handler derives directly from HttpOperationHandler and not from one of the generic overloads.

Example: extracting the user’s identity and add it as a parameter

The following code excerpt shows another example of an operation handler. This one extracts the user’s identity from the request’s headers, creates an IPrincipal and adds it as an parameter.

class PrincipalFromBasicAuthenticationOperationHandler : HttpOperationHandler<HttpRequestMessage,IPrincipal>
{
    public PrincipalFromBasicAuthenticationOperationHandler() : base("Principal")
    {
    }

    public override IPrincipal OnHandle(HttpRequestMessage input)
    {
        Console.WriteLine("PrincipalFromBasicAuthenticationOperationHandler.OnHandle");
        if (input.Headers.Authorization == null || input.Headers.Authorization.Scheme != "Basic")
        {
            // If properly configured, this should never happen:
            // this OperationHandler should only be used when 
            // Basic authorization is required
            throw new HttpResponseException(HttpStatusCode.InternalServerError);
        }
        var encoded = input.Headers.Authorization.Parameter;
        var encoding = Encoding.GetEncoding("iso-8859-1");
        var userPass = encoding.GetString(Convert.FromBase64String(encoded));
        int sep = userPass.IndexOf(':');
        var username = userPass.Substring(0, sep);
        var identity = new GenericIdentity(username, "Basic");
        return new GenericPrincipal(identity, new string[] { });
    }
}

This class derives from the genericHttpOperationHandler<HttpRequestMessage,IPrincipal>, since the input and output are known at compile time. The constructor calls the base constructor defining the output parameter’s name. The OnHandle method uses the Authorization header to extract the user’s identity, assuming that it was already validated (by the WCF runtime or by a message handler, see this post).

Since this handler adds an IPrincipal as a parameter, now any operation can use this interface as an input parameter

[ServiceContract]
class TheResourceClass
{
    [WebGet(UriTemplate="resources/{id}")]
    HttpResponseMessage GetSomething(HttpRequestMessage req, int id, IPrincipal principal)
    {
        ...
    }
}

Operation handler order

With message handlers, the execution order equals the configuration order. However, with operation handlers things are different. Since there could be handlers that need the output of other handlers, the execution order must satisfy this parameter dependency.

For example, consider an handler that receives an IPrincipal and uses it to evaluate an authorization policy. This handler must be executed after the above PrincipalFromBasicAuthenticationOperationHandler, in order to receive the user’s identity.

On startup, the WCF runtime uses the input and output handler information (via the OnGetInputParameters/OnGetOutputParameters methods) to compute a permutation of the configuration order that satisfies the input-output dependencies. If such an order doesn’t exists, an exception is throwed when the service starts.

The following diagram illustrates these dependencies.

OperationHandlers2

Configuration

The operation handlers can be configured via an operation handler factory, as the one showed in the next code excerpt

class MyOperationHandlerFactory : HttpOperationHandlerFactory
{
    protected override Collection<HttpOperationHandler> OnCreateRequestHandlers(ServiceEndpoint endpoint, HttpOperationDescription operation)
    {
        var coll = base.OnCreateRequestHandlers(endpoint, operation);
        if (operation.InputParameters.Any(p => p.Type.Equals(typeof(IPrincipal))))
        {
            var binding = endpoint.Binding as HttpBinding;
            if (binding != null && binding.Security.Transport.ClientCredentialType == HttpClientCredentialType.Basic)
            {
                coll.Add(new PrincipalFromBasicAuthenticationOperationHandler());
            }
        }
        return coll;
    }
}

Notice the following:

  • The call to the base.OnCreateRequestHandlers, so that the built-in handlers are also included in the collection.
  • The conditional addition logic, using service description information from the ServiceEndpoint and from HttpOperationDescription: the PrincipalFromBasicAuthenticationOperationHandler is only added if the operation requires an IPrincipal and the binding is using HttpClientCredentialType.Basic.

External resources

Finally, here are some interesting references about message handlers:

3 thoughts on “WCF Web API–Operation Handlers

  1. Daniel Quijada

    Is there a way I could validate my model objects before calling the operation, and throw an exception if object does’t meet validation policies? So far, I know I need to write an http operation handler, but I’m having troubles getting the object which is being sent so I can validate it!

    Reply
    1. pedrofelix Post author

      Yes, write an operation handler that declares an input parameter of the type of model that you want to validate.
      For that use a generic class (e.g. HttpOperationHandler) or declare it on the OnGetInputParameters

      Pedro

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s