Self-hosting Web API

Here I create a console application that is a self-hosting Web API (2) that uses OWIN. You must add the Microsoft ASP.NET Web API 2.1 OWIN Self Host Nuget package to the project. Once this is running you could easily move it to a Windows Service (see my other post to set that up).

Create a Program.cs:

using Microsoft.Owin.Hosting;
using System;
using System.Net.Http;

namespace JsonAPISelfHost
{
    class Program
    {
        public static bool Terminate { get; set; }
    
        static void Main(string[] args)
        {
            string baseAddress = "http://localhost:9000/";
            Terminate = false;

            //var options = new StartOptions();
            //options.Urls.Add("http://+:9000/"); //use this if you need to add SSL or other endpoints

            // Start OWIN host 
            using (WebApp.Start<Startup>(url: baseAddress))
            {
                // Create HttpCient and make a request to test api
                HttpClient client = new HttpClient();
                var response = client.GetAsync(baseAddress + "api/json").Result;
                
                Console.WriteLine(response);
                Console.WriteLine(response.Content.ReadAsStringAsync().Result);
                Console.ReadLine(); 
                
                //If hosting from a Windows service, set Terminate to true to stop the API
                //while (!Terminate)
                //{
                //    var t1 = new Thread(a => Thread.Sleep(10));
                //    t1.Start();
                //    t1.Join();
                //}                
            }
        }
    }
}

Next create the Startup.cs:

using Owin;
using System.Web.Http;

namespace JsonAPISelfHost
{
    public class Startup
    {
        // This code configures Web API. The Startup class is specified as a type
        // parameter in the WebApp.Start method.
        public void Configuration(IAppBuilder appBuilder)
        {
            // Configure Web API for self-host. 
            HttpConfiguration config = new HttpConfiguration();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            appBuilder.UseWebApi(config);
        } 
    }
}

Finally, add a controller and toss it into a Controllers folder:

using System.Collections.Generic;
using System.Web.Http;

namespace JsonAPISelfHost
{
    public class JsonController : ApiController
    {
        // GET api/json 
        //http://localhost:9000/api/json 
        [HttpGet]
        public IEnumerable Get()
        {
            return new string[] { "value1 from json", "value2 from json" };
        }

        // GET api/json/5 
        public string Get(int id)
        {
            return "value";
        }

        // POST api/json
        public void Post([FromBody]string value)
        {
        }

        // PUT api/json/5 
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/json/5 
        public void Delete(int id)
        {
        } 
    }
}
Run the project to test it. You can also point your browser to http://localhost:9000/api/json.

Custom routing

The routing used above works but it's kind of strange to make a call using api/controller. What is it really doing? It's doing a "get" on something called json but what's that? And what if I wanted to have multiple gets from the same controller? To make it more specific, we could adjust the routing so that it behaves more like conventional MVC. In this way it is more self-documenting IMO:

 config.Routes.MapHttpRoute(
    name: "CustomApi",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional }
 );

Next the controller would change:

[HttpGet]
public IEnumerable GetGems()
{
    return new string[] { "value1 from json", "value2 from json" };
}

And our endpoint would be:

http://localhost:9000/api/json/GetGems

Well that clears it up. Now I just need to know what gems are.

Notes

It is not necessary to create a URL reservation on your local machine using the code shown, but here it is for reference:

netsh http add urlacl http://+:9000/ user=everyone

What if I get a "HTTP Error 503. The service is unavailable"? You can't use OWIN with a start option URL and also have a URL reservation, it's one or the other. Best option would probably be to pass in the endpoint from a config.

How do you know if the machine is listening? Once the app is running, you would simply telnet to the machine using the port number and see if a connection is accepted:

telnet localhost 9000
Telnet is a Windows feature and is installed by using "Turn Windows features on/off".

What if I want Windows Authentication?

Simply add two lines to the Configuration method in Startup.cs and it becomes this:

public void Configuration(IAppBuilder app)
{
    //for windows authentication
    listener = (HttpListener)app.Properties["System.Net.HttpListener"];
    listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication;
    
    var config = new HttpConfiguration();

    config.Routes.MapHttpRoute(
        name: "CustomApi",
        routeTemplate: "api/{controller}/{action}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );

    app.UseWebApi(config);
}

Then use the [authorize] decorator on your controller.