Introduction
In this article we shall see different methods of WebAPI hosting. We will be creating a class library for API Controller and reference the same in various hosting projects. If you started working with WebAPI , soon you will start copy pasting the WebAPI controllers and related things over and over in each projects say you have planned to host one in Console or wish to perform unit testing or host the same in IIS as Web Application.
When you are hosting your WebAPI in IIS , all your API controllers gets compiled and will be available in the application domain so you can make a HTTP Web request to your API controller. But this isn't the case when you are hosting in a windows process (self hosting) by creating a class library and referencing the same. You will be surprised and wonder why it isn't working as expected.
There is currently a bug associated with the WebAPI framework, When you are hosting your WebAPI in a console or windows service using HttpSelfHostServer , the HttpControllerDispatcher is unable to map the incoming URL request to the API controller if you are trying to reference the WebAPI as a class library. So you see most of the WebAPI implementation hosted in console has the API controllers with in the same project. In fact, it is also the same case with integration or unit testing of API Controllers.
Here we will see how to overcome the above problem when we are creating a WebAPI library and trying to reference the same when you are hosting the WebAPI in ASP.NET , Console or Window Service etc
There are primarily two types of hosting available
1. Web Hosting - In this case Web API will be hosted on top of the classic ASP.NET hosting infrastructure, supported by the IIS (Internet Information Services) server.
2. Self Hosting - The WebAPI will be hosted on a Windows Process. One can either go with console or windows services.
One can also use in-memory hosting for unit testing the WebAPI Libraries. Below are two hosting adapters used for web and self hosting. They are also available as independent Nuget packages.
Microsoft.AspNet.WebAPI.WebHost and Microsoft.AspNet.WebApi.SelfHost
Before understanding the WebAPI hosting , lets first glance through the below diagram and understand the overall picture of different types of hosting to how the requests are dispatched to the API controller.

Background
Understanding of ASP.NET WebAPI. You can also refer my beginners article http://www.codeproject.com/Articles/549152/Introduction-to-ASP-NET-Web-API
Using the code
Step 1: Creating a new WebAPI Controller class and it's associated Entity in a class library project.
Create a new class library project say "ProductsLibrary" and then create a new ProductsController class inheriting ApiController. Implement WebAPI methods to get all products , products by id etc.
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
}
public class ProductsController : ApiController
{
public ProductsController()
{
}
Product[] products = new Product[]
{
new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 },
new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M },
new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M }
};
public IEnumerable<product> GetAllProducts()
{
return products;
}
public Product GetProductById(int id)
{
var product = products.FirstOrDefault((p) => p.Id == id);
if (product == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return product;
}
public IEnumerable<product> GetProductsByCategory(string category)
{
return products.Where(p => string.Equals(p.Category, category,
StringComparison.OrdinalIgnoreCase));
}
}
Create a CustomAssemblyResolver class implementing IAssembliesResolver interface. The GetAssemblies method implementation loads all the assemblies based on the path. We will be re-using this class in various other projects.
public class CustomAssemblyResolver : IAssembliesResolver
{
private string _path;
public CustomAssemblyResolver(string path)
{
_path = path;
}
ICollection<assembly> IAssembliesResolver.GetAssemblies()
{
List<assembly> assemblies = new List<assembly>();
assemblies.Add(Assembly.LoadFrom(_path));
return assemblies;
}
} Let us see how to host the WebAPI in a console application. Before hosting WebAPI , we will have to follow the below mentioned step to reserve the Url
Add an HTTP URL Namespace Reservation
This application listens to http://localhost:8081/. By default, listening at a particular HTTP address requires administrator privileges. Run Visual Studio with elevated administrator permissions, or Use Netsh.exe to give your account permissions to reserve the URL.
To use Netsh.exe, open a command prompt with administrator privileges and enter the following command:following command:
netsh http add urlacl url=http://+:8081/ user=machine\username . Where machine\username is your user account.
When you are finished self-hosting, be sure to delete the reservation:
netsh http delete urlacl url=http://+:8081/
Hosting the WebAPI in a Console App
1. Create a new console application and reference the ProductsLibrary.dll (The WebAPI class library project that we created).
2. Create an instance of HttpSelfHostConfiguration, set the Route and Services. It defines the self hosting configuration. Below you can see we are replacing the Services by dynamically loading the ProductsLibrary assembly. So there comes the use of CustomAssemblyResolver
3. Create an instance of HttpSelfHostServer, make use of the above host configuration.
4. Open connection to listen for the incomming HttpRequest to process.
static void Main(string[] args)
{
Uri _baseAddress = new Uri("http://localhost:8081/");
var assembly = System.Reflection.Assembly.GetExecutingAssembly().Location;
string path = assembly.Substring(0, assembly.LastIndexOf("\\")) + "\\ProductsLibrary.dll";
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(_baseAddress);
config.Services.Replace(typeof(IAssembliesResolver), new CustomAssemblyResolver(path));
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
HttpSelfHostServer server = null;
// Create server
server = new HttpSelfHostServer(config);
Console.WriteLine("Waiting for clients");
// Start listening
server.OpenAsync().Wait();
// Get All Products
GetAllProducts();
Console.ReadLine();
}
We will now try to make a HttpRequest to the WebAPI Controller and see whether we can get all the products. For that we need to create an instance of HttpClient and then perform GetAsync
private static async void GetAllProducts()
{
try
{
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(new Uri("http://localhost:8081/api/Products"));
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("********* Get request to get all products *******");
Console.WriteLine(responseBody);
Console.WriteLine("\n");
}
catch (HttpRequestException e)
{
Console.WriteLine("\nException Caught!");
Console.WriteLine("Message :{0} ", e.Message);
}
} The below picture depicts the Self Hosting of WebAPI

Hosting the WebAPI in IIS
1. Create a ASP.NET MVC4 Web application
2. Reference the ProductsLibrary , the WebAPI library that we had created.
You can notice the WebAPI Route registration all done by default when you are creating the project
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
3. In order to host this web application you can create a virtual directory in IIS and choose the Physical path i.e your Web project folder.
There is nothing special about this type of hosting. But the only difference you can see here is the ApiControllers are being referenced and it's not within the web application.
Below you can see how we are requesting for all products by specifying the Url to the Products API Controller.

In-Memory Hosting of WebAPI
If you are planning to perform unit or integration testing then this approch would be the best one. Two different things can be done.
1. Create an instance of HttpClient and HttpServer and make a WebAPI Request and can assert the response.
2. Create a custom DelegateHandler and then make of use HttpServer and HttpClient or HttpMessageInvoker to initiate a WebAPI request.
We will see both of these approches.
Below is the code snippet creates an instance of HttpConfiguration, sets the Routes
HttpConfiguration config;
[SetUp]
public void Setup()
{
config = new HttpConfiguration();
config.Routes.MapHttpRoute("Default", "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional });
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
}
Below is the code block for testing the GetAllProducts WebAPI functionality. Note we are replacing the HttpConfiguration's Services dynamically with the ProductsLibrary assembly.
1. Create a HttpServer instance with HttpConfiguration
2. Create a HttpClient instance with HttpServer.
3. Make a WebAPI request to get all products.
4. Assert the Products count and make sure the count is as expected.
[Test]
public void GetAllProductsWithOutMessageHandler()
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly().Location;
string path = assembly.Substring(0, assembly.LastIndexOf("\\")) + "\\ProductsLibrary.dll";
config.Services.Replace(typeof(IAssembliesResolver), new CustomAssemblyResolver(path));
HttpServer server = new HttpServer(config);
HttpClient client = new HttpClient(server);
HttpResponseMessage response = client.GetAsync("http:
var responseProducts = response.Content.ReadAsAsync<product[]>().Result;
Assert.AreEqual(responseProducts.Count(), 3);
}
The second method , we will make use of custom delegate handler and verify the same.
Note here we are using a InMemoryHttpContentSerialization handler. It's used to send the WebAPI request and format the response appropriately and send it across to the client. Frankly speaking , InMemoryHttpContentSerialization
just overrides the SendAsync method.
The InMemoryHttpContentSerialization Delegate handler does the below
1. Process the request message.
2. Call base.SendAsync to send the request to the inner handler.
3. The inner handler returns a response message. (This step is asynchronous.)
4. Process the response and return it to the
caller.
Note: Here the InnerHandler itself is HttpServer. So it is actually responsible for sending the WebAPI Requests.
You might find little difference in the way how we are performing the below unit tests by creating a HttpRequestMessage and initiate a WebAPI request using HttpMessageInvoker. We are still using HttpConfiguration , HttpServer instances however the MessageInvoker's SendAsync can make any type of WebAPI Request. The request in-turn is purely dependent upon the request method that we are setting.
The biggest advantage of using this approch is we can do some pre and post processing of Http Web Request and Response.
[Test]
public void GetProductsWithMessageHandler()
{
Uri uri = new Uri(baseAddress, "api/Products/GetAllProducts");
Product requestProduct = new Product()
{
Id = 1,
Name = "Tomato Soup",
Category = "Groceries",
Price = 1
};
HttpServer server = new HttpServer(config);
HttpMessageInvoker messageInvoker = new HttpMessageInvoker(new InMemoryHttpContentSerializationHandler(server));
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = uri;
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
request.Method = HttpMethod.Get;
CancellationTokenSource cts = new CancellationTokenSource();
using (HttpResponseMessage response = messageInvoker.SendAsync(request, cts.Token).Result)
{
var responseProducts = response.Content.ReadAsAsync<product[]>().Result;
Assert.NotNull(response.Content);
Assert.NotNull(response.Content.Headers.ContentType);
Assert.AreEqual("application/xml; charset=utf-8", response.Content.Headers.ContentType.ToString());
Assert.AreEqual(responseProducts.Count(), 3);
}
} Below is the code snippet for InMemoryHttpContentSerializationHandler
public class InMemoryHttpContentSerializationHandler : DelegatingHandler
{
public InMemoryHttpContentSerializationHandler()
{
}
public InMemoryHttpContentSerializationHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override Task<httpresponsemessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken).ContinueWith<httpresponsemessage>((responseTask) =>
{
HttpResponseMessage response = responseTask.Result;
response.Content = ConvertToStreamContent(response.Content);
return response;
});
}
private StreamContent ConvertToStreamContent(HttpContent originalContent)
{
if (originalContent == null)
{
return null;
}
StreamContent streamContent = originalContent as StreamContent;
if (streamContent != null)
{
return streamContent;
}
MemoryStream ms = new MemoryStream();
originalContent.CopyToAsync(ms).Wait();
ms.Position = 0;
streamContent = new StreamContent(ms);
foreach (KeyValuePair<string,>> header in originalContent.Headers)
{
streamContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
return streamContent;
}
} Below you can see when we are hosting the WebAPI In-Memory we are directly dealing with the HttpClient and HttpServer


References
http://blogs.msdn.com/b/kiranchalla/archive/2012/05/06/in-memory-client-amp-host-and-integration-testing-of-your-web-api-service.aspx
http://blogs.msdn.com/b/kiranchalla/archive/2012/05/05/asp-net-mvc4-web-api-stack-diagram.aspx
Points of Interest
It was really a good time in learning something new and playing around once again with WebAPI to understand the hosting tactics.
If you have any suggestions , comments or anything you want to say please post a comment. Also If you like the article please do vote for me.
History
Version 1.0 - 3/3/2013 - Initial version with a sample application to host the Web API in Console, IIS and In-memory hosting to unit test for the same.