Decorating ASP.NET Web API IHttpController

asp.net-web-api, c#, decorator, dependency-injection

Solution

I would say, that the natural, designed way how to achieve this behaviour in ASP.NET Web API is with the Custom Message Handlers / Delegation Handlers

For example I do have this `DelegationHandler` in place

public class AuthenticationDelegationHandler : DelegatingHandler
{
    protected override System.Threading.Tasks.Task<HttpResponseMessage> 
        SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // I. do some stuff to create Custom Principal
        // e.g.
        var principal = CreatePrincipal();
        ...

        // II. return execution to the framework            
        return base.SendAsync(request, cancellationToken).ContinueWith(t =>
        {
            HttpResponseMessage resp = t.Result;
            // III. do some stuff once finished
            // e.g.:
            // SetHeaders(resp, principal);

            return resp;
        });
    }

And this is how to inject that into the structure:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MessageHandlers.Add(new AuthenticationDelegationHandler());

Problem

I'm trying to wrap Web API controllers (`IHttpController` implementations) with decorators, but when I do this, Web API throws an exception, because somehow it is expecting the actual implementation. Applying decorators to controllers is a trick I successfully apply to MVC controllers and I obviously like to do the same in Web API. I created a custom `IHttpControllerActivator` that allows resolving decorated `IHttpController` implementations. Here's a stripped implementation: ``` public class CrossCuttingConcernHttpControllerActivator : IHttpControllerActivator { private readonly Container container; public CrossCuttingConcernHttpControllerActivator(Container container) { this.container = container; } public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) { var controller = (IHttpController)this.container.GetInstance(controllerType); // Wrap the instance in one or multiple decorators. Note that in reality, the // decorator is applied by the container, but that doesn't really matter here. return new MyHttpControllerDecorator(controller); } } ``` My decorator looks like this: ``` public class MyHttpControllerDecorator : IHttpController { private readonly IHttpController decoratee; public MyHttpControllerDecorator(IHttpController decoratee) { this.decoratee = decoratee; } public Task<HttpResponseMessage> ExecuteAsync( HttpControllerContext controllerContext, CancellationToken cancellationToken) { // this decorator does not add any logic. Just the minimal amount of code to // reproduce the issue. return this.decoratee.ExecuteAsync(controllerContext, cancellationToken); } } ``` However, when I run my application and request the `ValuesController`, Web API throws me the following `InvalidCastException`: Unable to cast object of type 'WebApiTest.MyHttpControllerDecorator' to type 'WebApiTest.Controllers.ValuesController'. Stacktrace: ``` at lambda_method(Closure , Object , Object[] ) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass13.<GetExecutor>b__c(Object instance, Object[] methodParameters) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.<>c__DisplayClass5.<ExecuteAsync>b__4() at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken) ``` It's just as if Web API supplies us with the `IHttpController` abstraction but skips it and still depends on the implementation itself. This would of course be a severe violation of the Dependency Inversion principle and make the abstraction utterly useless. So I'm probably doing something wrong instead. What I'm I doing wrong? How can I happily decorate my API Controllers?

Original source