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.
The resulting project looked like this:
The other option I had was to use the “Empty” template with Web API references.
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
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.
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 flavored Owin wrapper around HttpListener.
Installing the following Nuget into the Console app will get you started,
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 an HTTPServer and call Start. In Web API 2. X uses Katana bootstrapping code to get an 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.?
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:
I kept the WebApiConfig.The register method around just follows 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 an 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,
And for the Self Hosted Console, we need the Owin Host stuff.
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.
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.
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 flavored Owin? The answer, I believe, lies in some of those 34 NuGet packages that the template pulled in.
In a noble effort to build infrastructure that could be used on any Owin (with some Katana flavoring) 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 Nuggets 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 to 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,
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 of 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 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.
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:
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, 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.