Web API Cookie Cutter

The Simplest Possible ASP.NET Web API Template

I recently needed to create a new Web API project for some content I’m working on for a talk.  I decided I might as well use the ASP.NET Web API Template to get started.

Web API Cookie Cutter

The resulting project looked like this:

Visual Studio Solution Explorer EmptyProject

75 class files, 23 Razor templates, 34 unique Nuget packages, and 28 Javascript files before I wrote a single line of my own code.  I’m sure there is a ton of value in all of that code. However, I know that I don’t currently need most of it and far worse I don’t know what much of it does.  I really don’t like having code in my projects that I don’t understand, when I have the option of not having it there.

Bare Bones

The other option I had was to use the “Empty” template with Web API references.

Global.asax.cs

This template looks a whole lot more manageable but I prefer having my API related code in a separate project to my hosting code.

Separation Of Concerns

Like this,

Visual Studio EmptyProject2

The advantage of this approach is that each project gets considerably simpler in terms of dependencies.  It also allows me to add a console host project, which I find much easier for debugging purposes. 

Solution Explorer Empty Project 2

In order to run an API in a console we need to pull in the “Self Host” support libraries.  The way self host works changed in Web API 2.  Earlier versions used to be based on a thin WCF wrapper around HttpListener.  Since 2.0 it uses a Katana flavoured Owin wrapper around HttpListener. 

Installing the following Nuget into the Console app will get you started,

Install Package Owin.Hosting

Hello Magic Incantation

I’ve built self-host APIs using the old 1.0 Web API many times.  It’s a fairly simple process, create a configuration object, pass it to an instance of a HTTPServer and call Start.  In Web API 2.X it uses Katana bootstrapping code to get a HTTP server up and running.

There are two parts to bootstrapping in Katana.  One part is initializing the HTTP server and the other is initializing the Owin based application.  The challenge is finding the magic incantation code.  You need to call a static method on a class that is not the easiest to guess, and then you need to create a class that has to have a method with a signature that you need to guess.  Here is the article I found that reminded me how to do it.

The first is to call the static method Start on the WebApp class.

staticvoidMain(string[] args){    
  using(WebApp.Start<Startup>("http://127.0.0.1:12345"))    
  {        
    Console.ReadLine();    
  }
}

This code is in the Console Host project.  The Startup class which is referenced here should be in the API project.

The API project will need to take a dependency on the following Nuget in order to create the Startup class:

Install Package WebApi Owin
publicclassStartup{    
 publicvoidConfiguration(IAppBuilder app)    
 {        
  var httpConfiguration = newHttpConfiguration();        
  WebApiConfig.Register(httpConfiguration);        
  app.UseWebApi(httpConfiguration);    
 }
}

I kept the WebApiConfig.Register method around just follow the convention.  It could just as easily be in-lined.

There are a few gotchas to running self-host.  You either need to be running Visual Studio as an administrator, or you need to authorize the process to open a HTTP Server on the base URL you provide.  If you use localhost it will just work, however if you use any other URL you will need to set the URL ACL using netsh.

That Doesn’t Sound Too Painful

Seems pretty straight forward right?  For hosting in IIS/IISExpress you just use the Web Host Nuget packages.  The dependencies look like this,

Web ApI ASPNet
Packages Web API .core

And for the Self Hosted Console we need the Owin Host stuff.

Microsoft Owin Hosting
Packages Owin

The actual API project that contains all the controllers is just a class library project and only really needs access to the Core Web API nugets and the Web API to Owin adapter.

Microsoft AspNet Client
Microsoft Aspnet Client

Here Is Where It Gets Whacky

The confusion starts if you go and look back at the normal non-empty ASP.NET template project.  It’s a web hosted project but there is a Startup class in there.  Actually, there are two Startup classes in there that are defined as partial classes for extra bonus confusion.

Startup.cs
Startup.cs

So, if we are using Microsoft.AspNet.WebApi.WebHost for hosting the API, why do we need a Startup class that is part of Katana flavoured Owin?  The answer, I believe, lies in some of those 34 nuget packages that the template pulled in.

Microsoft Owin Security
Microsoft OWin Security

In a noble effort to build infrastructure that could be used on any Owin (with some Katana flavouring) compatible application, the security modules are built as Owin middleware. 

The absolute irony of this is the original Owin community went to great lengths to define the Owin interface in a way that required zero binary dependencies.  Unfortunately, Katana decided binary dependencies were necessary for “ease of use” and so a bunch of Katana/Owin related Nugets need to be pulled in to support these pieces of middleware, even though Owin is not actually being used to abstract away the host!

And It Gets Worse

Earlier I mentioned there were some magic incantations necessary to get the Katana host going.  And then the Katana host would call into the Startup class.  The problem is, the Webhost doesn’t need use this magic.  It uses the different Global.asax WebApiApplication magic for bootstrapping.  So, how do these pieces of Security middleware get fired up?

Enter a new guest to this party,

Microsoft Owin Host
Microsoft Owin Host

This is one of those packages that I consider EVIL (ok, so maybe I exaggerate).  This package causes a DLL to be referenced that makes stuff happen just because I referenced it.  That’s just nasty.  Anyway, this package is what you use to host an Owin-ish application using IIS.  I believe it contains the equivalent to WebApp.Start to fire up the Startup class.  This allows the security middleware to do its thing. [update: thanks to James’ comment, I found an article that talks more about the SystemWeb startup process]

So here is the question.  The default Web API template references both Microsoft.Owin.Host.SystemWeb and Microsoft.AspNet.WebApi.WebHost, it contains a Global.asax and Startup classes.  Which of these two mechanisms, both of which are capable of connecting a WebAPI application to IIS is actually being used?  I have no idea and considering everything is changing again in MVC6, I have little motivation to go spelunking.  However, if I can avoid it, I’m not going to have both in the same project.  Who knows what subtle interactions exist between the two mechanisms.

Simplicity Rules

In the end, I decided to remove the Microsoft.AspNet.WebApi.WebHost reference from my WebHost project and stick with just the Owin hosting layer.  This left my Web project with just these dependencies:

Owin host
Package Microsoft Owin

Note that my web host project now has no dependencies at all on Web API.  Even more freaky is that, there isn’t any code at all in the Web Host project.  The Microsoft.Owin.Host.SystemWeb  magically bootstraps the Startup class that is in the referenced API Project.  The Console host project also has no dependencies on Web API and my API project has no dependency on hosting related code.  That’s what Owin is supposed to do.  But when everything is mashed up into a single project, you don’t see the isolation benefits.

I’ve posted a complete project structure up on Github.  It doesn’t have built in security, or account management, or help pages, but I’m considering doing future posts on how to add those in incrementally.

I’m not completely sure whether I wrote this post simply to get this stuff straight in my head, or whether this might actually be useful for others who are struggling to see how all the pieces fit together.  So, if you find this kind of post useful, let me know.

Image Credit: Cookie Cutter https://flic.kr/p/95hFLk

Related Blog