MVC

Using Ninject with Web-Api 2

#Using Ninject with ASP.NET Web API 2

I thought I would write a quick post on how to use Ninject as an IOC container when using Web API 2. I must admit, this was not a great experience when I tried it first, mainly as I was unaware of all the supplimentary Ninject packages I needed to get this working. Hopefully this post saves you from having to go through the same pain.

Please note that my approach only touches how to use Ninject when using IIS/IIS-Express as a hosting layer.

Setting up the Web API solution

We start by creating a very simple Web API solution. Using the visual studio templates (note: I am using VS2015 community edition) I create a new ASP.NET Web Application project, using the Empty Project template with references for all Web API assemblies. My project structure currently looks like this:

screen1.PNG

If you get a list of all packages installed at this point, you should see something along the lines of

PM> get-package

Id Versions ProjectName
-- -------- -----------
Microsoft.AspNet.WebApi {5.2.3} ApiWithNinject
Microsoft.AspNet.WebApi.Client {5.2.3} ApiWithNinject
Microsoft.AspNet.WebApi.Core {5.2.3} ApiWithNinject
Microsoft.AspNet.WebApi.WebHost {5.2.3} ApiWithNinject
Microsoft.CodeDom.Providers.DotN... {1.0.0} ApiWithNinject
Microsoft.Net.Compilers {1.0.0} ApiWithNinject
Newtonsoft.Json {6.0.4} ApiWithNinject

Setting up the Message Controller example

For the sake of brevity, I am going to use a simple controller callect MessageController. The intent here is for the api controller to retrieve and serve a message from an IMessageService instance, which will be injected via the controllers constructor (by Ninject). These are the main classes that make up my example:

public interface IMessageService
    {
        string Message();
    }
public class MessageService : IMessageService
    {
        public string Message()
        {
            return "Hello from the Message Service";
        }
    }
    public class MessageController : ApiController
    {
        private IMessageService _messageService;
        public MessageController(IMessageService messageService)
        {
            _messageService = messageService;
        }

        [Route("api/message")]
        public HttpResponseMessage GetMessage() {
            return Request.CreateResponse(HttpStatusCode.OK, _messageService.Message());
        }
    }

Note that I am using HttpAttributeRoutes to specify the routes. Ensure it is enabled when configuring web api on startup (from the Global.asax)

public class MessageService : IMessageService
public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            //......
        }
    }

At this stage, a GET request aimed at the resouce /api/message will result in a 500 error since Web API obviously has no concept of how to inject the IMessageService into the api controller’s constructor.

Installing required Ninject packages

We are now in a position to wire up Ninject within our solution. Bear in mind that there are some supplementary packages required based on how you choose to host your API. Since we are using IIS hosting, we will grab the following packages as listed in the Ninject docs.

Ensure you have the following Nuget packages installed:
* Ninject
* Ninject.Web.WebApi.WebHost (NOTE: this package was not listed as required in the documentation but has a dependency on Ninject.Web.Common.WebHost anyway)

At this point, your list of installed packages should look something like:

PM> get-package

Id Versions ProjectName
-- -------- -----------
Microsoft.AspNet.WebApi {5.2.3} ApiWithNinject
Microsoft.AspNet.WebApi.Client {5.2.3} ApiWithNinject
Microsoft.AspNet.WebApi.Core {5.2.3} ApiWithNinject
Microsoft.AspNet.WebApi.WebHost {5.2.3} ApiWithNinject
Microsoft.CodeDom.Providers.DotN... {1.0.0} ApiWithNinject
Microsoft.Net.Compilers {1.0.0} ApiWithNinject
Microsoft.Web.Infrastructure {1.0.0.0} ApiWithNinject
Newtonsoft.Json {6.0.4} ApiWithNinject
Ninject {3.2.2.0} ApiWithNinject
Ninject.Web.Common {3.2.0.0} ApiWithNinject
Ninject.Web.Common.WebHost {3.2.3.0} ApiWithNinject
Ninject.Web.WebApi {3.2.0.0} ApiWithNinject
Ninject.Web.WebApi.WebHost {3.2.4.0} ApiWithNinject
WebActivatorEx {2.0} ApiWithNinject

Wiring up Ninject for DI

Having installed Ninject.Web.Common.WebHost will have introduced the templated NinjectWebCommon class within your App_Start folder. Aside from configuring a BootStrapper etc, this is where the framework provides an extension point for you to specify your Ninject bindings etc.

The template generates a RegisterServices method. This is where we will add our bindings to allow injecting the messaging service.

public static class NinjectWebCommon 
    {
        //Truncated for brevity...
        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<IMessageService>().To<MessageService>();
        }        
    }       

At this point, I found that trying to run the project resulted in the following exception being thrown. To date, I am still unsure why this is being thrown when using ninject right out the box.

Ninject.ActivationException was unhandled by user code
HResult=-2146233088
Message=Error activating HttpConfiguration
More than one matching bindings are available.
Matching bindings:
1) binding from HttpConfiguration to method
2) binding from HttpConfiguration to method
Activation path:
1) Request for HttpConfiguration

A simple fix for this was to simply instruct the kernel to rebind the instance of the HttpConfiguration used. Going back to the NinjectWebCommon class, I made the following change in the CreateKernel method:

public static class NinjectWebCommon 
    {
    	//Truncated for brevity...

        private static IKernel CreateKernel()
        {
            var kernel = new StandardKernel();

            //Instruct the Kernel to rebind the HttpConfiguration to the default config instance provided from the GlobalConfiguration
            kernel.Rebind<HttpConfiguration>().ToMethod(context => GlobalConfiguration.Configuration);
            
            try
            {
                kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
                kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

                RegisterServices(kernel);
                return kernel;
            }
            catch
            {
                kernel.Dispose();
                throw;
            }
        }    
    }       

At this point, all my code compiles just fine, the application is successfully hosted within IIS (express) and my resource requests work just fine

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?UzpcV29ya3NwYWNlXGdpdGh1YlxwaXJhbnN3b3JsZFx1c2luZy1uaW5qZWN0LXdpdGgtd2ViLWFwaS0yXHNyY1xBcGlXaXRoTmluamVjdFxhcGlcbWVzc2FnZQ==?=
X-Powered-By: ASP.NET
Date: Sun, 20 Sep 2015 09:38:05 GMT
Content-Length: 32

"Hello from the Message Service"

Hope this saves you from having to go through the same pains that I did. Feel free to grab my code from Github

Responding to requests without the use of the MVC execution pipeline

If you are working with an ASP.Net MVC web application, you may run into a situation where you need to process and respond to certain incoming web requests outside of the normal MVC execution pipeline. If I am honest, I do not have a concrete use-case for why anyone would need to do this, as in my opinion the framework should be extensible enough to meet most of your needs. Hence only proceed if you have a very good reason (and please leave a comment below to share what it is).

For the sake of simplicity, I am going to illustrate this with a very simple example. Lets assume we have an existing MVC application where we want to identify a particular request that contains an id parameter, eg /show-id?id=123. We wish to respond without having to invoke the MVC execution pipeline, i.e. without the use of controllors, actions, views etc. We simply wish to extract the id and print it out as part of the response.

Identify and intercept incoming requests to process

We begin with a way to identify the incoming web requests that we will respond to. In an MVC application this is done by registering a route (i.e. an instance of RouteBase), which outlines the pattern of the url to match against, from which the framework can establish which controller/action to invoke. All your routes should be registered with the RouteTable on application startup.

We create an extension of the RouteBase class to allow us to identify the route. On every incoming web request, the GetRouteData method is called where the route is responsible for evaluating if it should respond to the request. We simply check to ensure that the request path matches our expected route /show-id. Returning a non-null instance of the RouteData class indicates a match.

public class PrintIdRoute : RouteBase
    {
        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            if (httpContext.Request.Path.ToLower() != "/show-id")
                return null;
            return new RouteData();
        }
    }

Next we need to register our custom route. Remember that the routing framework evaluates routes sequentially in the order in which they were registered. The first route to return a match is then tasked with responding to the request. To ensure our route is registered ahead of all the others, I edit the Application_Start method in my application’s Global.asax file like so:

public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            var routeCollection = RouteTable.Routes;
            
            //add custom route before registering all other routes
            routeCollection.Add(new PrintIdRoute());
            
            //Register all other MVC routes
            RouteConfig.RegisterRoutes(routeCollection);
        }
    }

Note: In an effort to maintain proper seperation of concern, you should not deal with route registration directly within the Global.asax. Ensure you apply proper software practises when actually implementing your solution.

Create a Route Handler to respond to the pattern match

The PrintIdRoute class we have created should only be responsible for matching an incoming URL and return a non-null RouteData instance to signify a match. The responsibility of identifying who is responsible for processing the request lies with the IRouteHandler interface. It contains a sole method GetHttpHandler which is used to construct an instance of an IHttpHandler which in turn is responsible for processing the request.

To illustrate the whole process, here is a summarized excerpt from the ProcessRequest method of the UrlRoutingHandler, which is called in response to an incoming web request:

protected virtual void ProcessRequest(HttpContextBase httpContext)
    {
      //Iterate through all the routes and see if any routes return a match
      RouteData routeData = this.RouteCollection.GetRouteData(httpContext);

      //Get the IRouteHandler from the returned routeData class
      IRouteHandler routeHandler = routeData.RouteHandler;

      //Capture the state of the current web request using a RequestContext
      RequestContext requestContext = new RequestContext(httpContext, routeData);

      //Get the IHttpHandler and allow it to process the request
      IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
      VerifyAndProcessRequest(httpHandler, httpContext);
    }

When mapping routes within the MVC framework, the values of IRouteHandler and IHttpHandler default to an instance of System.Web.Mvc.MvcRouteHandler and the System.Web.Mvc.MvcHandler respectively. The MvcRouteHandler, prior to creating the MvcHandler, deals with other issues like configuring the session state behaviour. The MvcHandler on the other hand is what initializes the entire MVC framework’s processing pipeline, i.e. the process of invoking the controller & action to respond to the request etc.

We create our own ‘IRouteHandler’ implementation PrintIdRouteHandler which will serve up an instance of our IHttpHandler implementation PrintIdHttpHandler:

public class PrintIdRouteHandler : IRouteHandler
    {
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            return new PrintIdHttpHandler();
        }
    }
public class PrintIdHttpHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            throw new NotImplementedException();
        }

        public bool IsReusable { get; private set; }
    }

We then ensure our custom routehandler is returned by our custom route upon a successful match. We do this by revisiting the PrintIdRoute class implementation:

public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            if (httpContext.Request.Path.ToLower() != "/show-id")
                return null;
            var routeData = new RouteData
            {
                RouteHandler = new PrintIdRouteHandler()
            };
            return routeData;
        }

Processing the request

The last step in the process involves implementing the ProcessRequest method within the PrintIdHttpHandler to respond to the incoming request.Before we can do this, remember our aim is to read and print out the value of the id url parameter within the result. We go back to our PrintIdRoute implementation:

public class PrintIdRoute : RouteBase
    {
        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            if (httpContext.Request.Path.ToLower() != "/show-id")
                return null;

            var routeData = new RouteData
            {
                RouteHandler = new PrintIdRouteHandler()
            };
            var id = httpContext.Request.Params["id"];
            routeData.Values["id"] = id;
            return routeData;
        }
    }

We simply extract the value from the url parameter from the incoming request. The RouteData class offers a Values dictionary which allows a route to extract values from the incoming request and pass them further down the processing pipeline. Once this is done, we can instruct the PrintIdRouteHandler to pass this value to the constructor of the PrintIdHttpHandler class during creation:

public class PrintIdRouteHandler : IRouteHandler
    {
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            int id = 0;
            var o = requestContext.RouteData.Values["id"] as string;
            int.TryParse(o, out id);
            return new PrintIdHttpHandler(id);
        }
    }

     public class PrintIdHttpHandler : IHttpHandler
    {
        private readonly int _id;

        public PrintIdHttpHandler(int id)
        {
            _id = id;
        }
        //.....
    }

Finally we implement the ProcessRequest method to write the result to the response

public void ProcessRequest(HttpContext context)
        {
            var message = string.Format("Recieved Id:{0}", _id);
            context.Response.Write(message);
        }

Hence if everything is wired up correctly, we can now run the solution and navigate to the expected route we should see something similar to:
screen1.PNG

Although our example is extremely contrived for the sake of simplicity, you should note that by electing to bypass the normal MVC execution pipeline, we have elected to forgo all the convenience and security features offered by the MVC framework. Hence I do not recommend using this approach unless you have a pressing need/concern that the framework cannot cater for. If anything I hope it has helped shed more light on how the MVC processing pipeline is invoked.

Feel free to download the source code for this example from Github