Unit testing DelegatingHandler

The DelegatingHandler in the MVC 4 beta Web API is not particularly easy to test due to the inheritance dependency on DelegatingHandler and the use of overridden protected methods. All is not lost though, by using the following pattern you can achieve testability of the logic with subtle changes to your existing DelegatingHandler and without breaking the Russian Doll pattern.

Create a delegate as follows:

public delegate Task<HttpResponseMessage> BaseSendAsyncDelegate(HttpRequestMessage request, CancellationToken cancellationToken);

Changing your DelegatingHandler to the following (note you’ll also need to add InternalsVisibleTo attribute for your unit test to see the handler):

public class MyTestableDelegatingHandler : DelegatingHandler
{
    internal Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken, BaseSendAsyncDelegate baseSendAsync)

{

        // Your before logic
        // …
       
return baseSendAsync(request, cancellationToken).ContinueWith(
            task =>
                {
                    HttpResponseMessage response = task.Result;
                       
                    // Your after logic
                   
return response;
            });
    }       
      
    protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        // Don’t put anything else in this method
       
return this.SendAsync(request, cancellationToken, (r, c) => base.SendAsync(r, c));
    }
}

Tests

Now the logic can be called without the overhead of the DelegatingHandler as follows:

[TestMethod]
public void MyTest()
{
    MyTestableDelegatingHandler logic = new MyTestableDelegatingHandler();
    HttpRequestMessage requestMessage = new HttpRequestMessage();

    Task<HttpResponseMessage> result = logic.SendAsync(
        requestMessage,
        new CancellationToken(false),
        (rm, ct) =>
            {

                // Do some Asserts in here for any “Before” logic

                // This simulates what the inner handler (or ultimately the controller) would return
                var task = new Task<HttpResponseMessage>(() => new HttpResponseMessage(HttpStatusCode.OK));
                task.Start();
                return task;
            });

    HttpResponseMessage resultMessage = result.Result;
    var status = resultMessage.StatusCode;
   
    // Do Asserts here for any “After” logic
}

Advertisements

MVC4 Web API–REST Sub-resources

To create sub-resources (e.g. /books/1/authors) in the Web API that shipped with MVC beta 4, you can create a “SubResourceControllerFactory” to mangle the controller name to include a sub controller as follows:

public class SubResourceControllerFactory : DefaultHttpControllerFactory
{
    public SubResourceControllerFactory(HttpConfiguration configuration) : base(configuration)
    {
    }

    public override System.Web.Http.Controllers.IHttpController CreateController(System.Web.Http.Controllers.HttpControllerContext controllerContext, string controllerName)
    {
        if (controllerContext.RouteData.Values.ContainsKey("subcontroller"))
        {
            return base.CreateController(controllerContext, controllerName + controllerContext.RouteData.Values["subcontroller"]);
        }

        return base.CreateController(controllerContext, controllerName);
    }
}

This factory can be instantiated using a custom IDependencyResolver that’s looking for a type of IHttpControllerFactory, for example in Global.asax.cs (Application_Start):

GlobalConfiguration.Configuration.ServiceResolver.SetResolver((type) =>
    {
        if (type == typeof(IHttpControllerFactory))
        {
            return new SubResourceControllerFactory();
        }
    });

Finally you create a route similar to:

routeCollection.MapHttpRoute("SubController", "api/{controller}/{id}/{subcontroller}/{subId}", new { subId = RouteParameter.Optional })