Introduction
To make a Web API unit testable, we have to initialize the dependent interfaces via the controller’s constructor. The challenge with MVC Web API is that when an HttpRequest
is made, the IHttpControllerActivator
class tries to initialize the controller based on which controller has been selected and passed on by HttpControllerDispatcher
class. By default, IHttpControllerActivator
looks for a parameter-less constructor. Hence, if we are using dependency injection (DI) in our Web API, we usually get errors that look like this:
{
"Message":"An error has occurred.",
"ExceptionMessage":"An error occurred when trying to
create a controller of type <your controller name>.
Make sure that the controller has a parameterless public constructor.",
"ExceptionType":"System.InvalidOperationException",
"StackTrace":"
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create
(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor,
Type controllerType)\r\n
at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController
(HttpRequestMessage request)\r\n
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
"InnerException":{
"Message":"An error has occurred.",
"ExceptionMessage":"Type <controller type> does not have a default constructor",
"ExceptionType":"System.ArgumentException",
"StackTrace":" at System.Linq.Expressions.Expression.New(Type type)\r\n
at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator
(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create
(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor,
Type controllerType)"
}
}
Solution
To solve this problem and still have a unit testable code written using DI, we have to register a dependency resolver with our HttpConfiguration
class.
The Code
In the WebApiConfig.cs file, where all the configurations are registered with our HttpConfiguration
class, we have to assign our UnityContainer
that holds all the dependency resolution rules, to the DependencyResolver
property of HttpConfiguration
instance.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var container = <Register all dependencies here>;
config.DependencyResolver = new UnityResolver(container);
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
The moment this registration of dependency resolver is done, the framework knows how to resolve the interfaces that are needed in the controller’s constructor, and hence can get through the GetInstanceOrActivator
method successfully.
Point of Interest
This kind of registrations and DI hooking helps us start the unit testing right from the controller methods as compared to testing only the business libraries separately.