Hosting Web API in Windows service

Running your api as Windows services can have multiple advantages, especially when working on bigger projects. This allows for multiple (services to run in isolation and gives fine grained control over your system components.

ASP.NET Web API ships with self-hosting feature that allows to run HTTP service outside of IIS. This can be easily used in Windows services. In this blog post I am going to show how to host Web API service inside of Windows service, using both Windows Service Visual Studio project template and Topshelf library.

Please note that I am using Visual Studio 2012 RC and Web API nightly build NuGet packages in the following examples.

Project setup

Start off by creating a new Windows service project.

Now, add reference to ASP.NET Web API. I'm taking advantage of NuGet and nightly build packages, but Web API RC pieces should work as well. If you are looking for instructions, check this blog post by Henrik F Nielsen.

Implementation

The implementation is straightforward, we just need to create HttpSelfHostServer instance and call OpenAsync when the service starts.
For the sake of simplicity I've skipped logging and xml configuration (to configure service address).

public partial class HttpApiService : ServiceBase  
{
    private HttpSelfHostServer _server;
    private readonly HttpSelfHostConfiguration _config;
    public const string ServiceAddress = "http://localhost:2345";

    public HttpApiService()
    {
        InitializeComponent();

        _config = new HttpSelfHostConfiguration(ServiceAddress);
        _config.Routes.MapHttpRoute("DefaultApi",
            "api/{controller}/{id}",
            new {id = RouteParameter.Optional});
    }

    protected override void OnStart(string[] args)
    {
        _server = new HttpSelfHostServer(_config);
        _server.OpenAsync();
    }

    protected override void OnStop()
    {
        _server.CloseAsync().Wait();
        _server.Dispose();
    }
}
public class ApiServiceController : ApiController  
{
    public string Get()
    {
        return "Hello from windows service!";
    }
}

Installation

The easiest way to install and test your service is using installutil.exe utility. Open your visual command prompt as administrator and go to bin\Debug folder of your service. To install it run:

installutil Piotr.ApiWindowsService.Service.exe

To uninstall:

installutil /u Piotr.ApiWindowsService.Service.exe

You may want to follow these instructions and add service installer along with a separate setup project to install your service. This would enable you to

Alternative approach - using Topshelf

Topshelf is a project aimed to simplify development and management of windows services. You can get it throught NuGet or download it on project's website.

Let's try to use it to host web api http server.

Create a new console applicaton and add a class library project to contain your service.

public class HttpApiService  
{
    private readonly HttpSelfHostServer _server;
    private readonly HttpSelfHostConfiguration _config;
    private const string EventSource = "HttpApiService";

    public HttpApiService(Uri address)
    {
        if (!EventLog.SourceExists(EventSource))
        {
            EventLog.CreateEventSource(EventSource, "Application");
        }
        EventLog.WriteEntry(EventSource,
            String.Format("Creating server at {0}",
            address.ToString()));
        _config = new HttpSelfHostConfiguration(address);
        _config.Routes.MapHttpRoute("DefaultApi",
            "api/{controller}/{id}",
            new { id = RouteParameter.Optional }
        );
        _server = new HttpSelfHostServer(_config);
    }

    public void Start()
    {
        EventLog.WriteEntry(EventSource, "Opening HttpApiService server.");
        _server.OpenAsync();
    }

    public void Stop()
    {
        _server.CloseAsync().Wait();
        _server.Dispose();
    }
}

Please note that the service class is a plain object and does not extend any special classes. Topshelf uses logical services which makes them easily reusable outside of windows service context. I would say this is one of advantages over 'classic' approach presented earlier.

In your console app project you need to include hosting code. Topshelf gives you some flexibility on how you can actually host your service(s) (eg. shelving) , which is nicely decoupled from service implementation details.

static void Main(string[] args)  
{
    HostFactory.Run(x =>
    {
        x.Service<HttpApiService>(s =>
        {
            s.SetServiceName("Piotr.WebApiTopShelfService");
            s.ConstructUsing(name => new HttpApiService(new Uri("http://localhost:1234")));
            s.WhenStarted(tc => tc.Start());
            s.WhenStopped(tc => tc.Stop());
        });
        x.RunAsLocalSystem();
        x.StartManually();
        x.SetDescription("Sample Web API Windows service");
        x.SetDisplayName("Piotr.WebApiTopShelfService");
        x.SetServiceName("Piotr.WebApiTopShelfService");
    });
}

This is basically all you need to do to implement a simple Web API service using Topshelf. To install it issue following command as administrator:

Piotr.WebApiTopShelfService.exe install

To uninstall:

Piotr.WebApiTopShelfService.exe uninstall

Once you start your service,

you should be able to make HTTP requests to your self hosted Web API server.

That's it! ASP.NET Web API self hosting features enabled us to use Windows service as a hosting process with minimal effort.

comments powered by Disqus