November 26, 2014

Befriending ASP.NET Web.API2, OWIN and Ninject

There are many articles where people writing about how to use WebAPI + Owin, much less talking about Owin + Ninject and very little gathering all together. Also in these rare articles I couldn't find working solution, so I decided to put all eggs in one basket and write how to use WebAPI + Owin + Ninject. It's very strange that most of the posts talking about using Unity, not Ninject, which I love the most (think not only I).

First, let's prepare our environment, I'm using Visual Studio 2013, but if you are still VS2012 user, you can download ASP.NET and Web Tools 2013.1 for Visual Studio 2012 from Microsoft site. Now we are ready to rock!

1. Create new solution. Choose Empty ASP.NET Web application

2. Download required packages from NuGet. I prefer to use Package Manager Console rather than UI form (hello from 90th). Also we won't download all packages at once, to understand what libraries will be needed at every step.
Install-Package Microsoft.AspNet.WebApi.Owin
Install-Package Microsoft.Owin.Host.SystemWeb
3. Create in you root directory file Startup.cs, which will be fired once when application starts.
public class Startup
{
 public void Configuration(IAppBuilder app)
 {
  var config = new HttpConfiguration();
  WebApiConfig.Register(config);

  app.UseWebApi(config);
 }
}
HttpConfiguration responsible for API routes. Routes itself described in WebApiConfig class, which will be automatically created with selected template.
Extension method UseWebApi allow us to wire up ASP.NET Web API to our Owin server pipeline.

4. Since we use Startup.cs for start-up configuring, feel free to delete Global.asax file

5. Add an interface for the service, the actual service and controller where our service will be injected
HomeController.cs
[RoutePrefix("api/home")]
public class HomeController : ApiController
{
 private readonly IFakeService _fakeService;

 public HomeController(IFakeService fakeService)
 {
  _fakeService = fakeService;
 }

 [Route("")]
 public IHttpActionResult Index(string question)
 {
  if (_fakeService.GetAnswer(question))
   return Ok();

  return BadRequest();
 }
}
IFakeService.cs
public interface IFakeService
{
 bool GetAnswer(string question);
}
FakeService.cs
public class FakeService : IFakeService
{
 public bool GetAnswer(string question)
 {
  return question.Contains("Is");
 }
}

6. Now it's time to install Ninject and related extensions
Install-Package Ninject.Web.Common.OwinHost
Install-Package Ninject.Web.WebApi.OwinHost

7. And the final steps to make all stuff works.
Create NinjectConfig.cs file
public static class NinjectConfig
{
 public static Lazy<IKernel> CreateKernel = new Lazy<IKernel>(() =>
 {
  var kernel = new StandardKernel();
  kernel.Load(Assembly.GetExecutingAssembly());

  RegisterServices(kernel);

  return kernel;
 });

 private static void RegisterServices(KernelBase kernel)
 {
  kernel.Bind<IFakeService>()
   .To<FakeService>();
 }
}
Add dependency assembly to section runtime of Web.config
<dependentAssembly>
 <assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" />
 <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.2.2.0" />
</dependentAssembly>
Change Startup.cs file this way
public class Startup
{
 public void Configuration(IAppBuilder app)
 {
  var config = new HttpConfiguration();
  WebApiConfig.Register(config);

  app.UseWebApi(config);
  app.UseNinjectMiddleware(() => NinjectConfig.CreateKernel.Value);
  app.UseNinjectWebApi(config);
 }
}
That's all. Now you can send POST request to your controller like this
http://localhost:PORT/api/home?question=QUESTION_STRING 
and see there is no error with absence parameterless public constructor. Happy coding!

Full code available on github

8 comments:

  1. For some reason package manager installs 3.2.0.0 of ninject libraries and it errors out on app.UseNinjectMiddleware. Once I force it to install 3.2.4.0 then it finally started working.

    ReplyDelete
    Replies
    1. Very interesting, I'll take it into account for researching this problem.

      Delete
  2. Would this take care of automatically disposing of resources for classes that implement the IDisposable interface?

    ReplyDelete
    Replies
    1. I'm not sure I understood your question correct. Could you specify what kind of classes do you mean, please?

      Delete
  3. How about to use ninject with custom attribute like:
    public class HMACAuthenticationAttribute : Attribute, IAuthenticationFilter{....}

    ReplyDelete
    Replies
    1. It's all up to you. I haven't considered the question of authorization here.

      Delete