Nowadays, when developing desktop applications for Windows, we have many options when choosing the .Net technology to use:
If the target is Windows 8 we can add even more choices to the pile, for example using HTML5 and Javascript, due the support of the new WinRT architecture.
Recently I had to analyze a scenario where a windows service should be developed, which would be responsible to run some kind of scheduled tasks - polling a SaaS service on the public internet, and integrate some data with on-premises systems. Additionally, a graphical tool should also be developed, to allow to configure some aspects of the windows service (instead of editing configuration files by hand).
For the UI tool, my first approach was to choose a WPF application. But I have no experience at all with WPF, and as a developer I am more comfortable with the web stack development, which means that on the client side I would like to use Html5 and Javascript, and the UI tool would be running on the browser.
Since I'm in love with AngularJS, my wish was to develop the tool using AngularJS. But I don't want to complicate the installation process, requiring my tool to be hosted in Internet Information Service (IIS). So, what I really want is to install my window service, which besides the integration logic, should also host my AngularJS application.
Well, in fact, what I really need is to have some kind of embedded web server that supports:
With this goal in mind, it's time to meet OWIN (Open web Interface for .Net) specification and the Katana Project.
From the OWIN site
OWIN defines a standard interface between .NET web servers and web applications. The goal of the OWIN interface is to decouple server and application, encourage the development of simple modules for .NET web development, and, by being an open standard, stimulate the open source ecosystem of .NET web development tools.
So, basically, OWIN is a spec which allows components to be reused on different web servers.
The Katana Project is a collection of projects to support OWIN with various Microsoft components. It is also a command line application for running self-host servers. To have a great overview of the Katana project read this post.
Ok, stop theory, and show me the how can I use Katana to embed a small web server on my windows service. which allows me to build an AngularJS app. Here we go!
First, let's create a new Visual Studio project, choosing the type Windows Service
Next, let's make some modifications to the project to allow us to test without having to install the windows service:
Now let's start to embed our web server. We will need some nuget packages
The first NuGet we will need it's the Microsoft.Owin.Hosting, which allow us to have a basci OWIN hosting in our application
Notice that the package is a pre-release version, so we should change the option in the drop down "Stable Only" to "Include Prerelease". To create our web application host, we just need to modify out internal start and call the method WebApplication.Start, indating the listen url as parameter (http://localhost:12345).
The Start method is a generic method, where we have to tell what is the class responsible to do the initial startup, which in our case it is the WebStartup class. By convention, the method to be called it is named Configuration, receiving the application builder object as an argument
Let's try to run our application, hitting F5, to see what happens
We are getting an exception, telling us that the HTTP Listener is not found.
Could not load file or assembly 'Microsoft.Owin.Host.HttpListener' or one of its dependencies. The system cannot find the file specified.
Until now, what we did was just adding the hosting capabilies to our application. We need to specify the OWIN component that should listen for and serve HTTP requests. Let's add the Microsoft.Owin.Host.HttpListener NuGet, which is the OWIN component that uses the Microsoft Windows HTTP protocol stack (http.sys)
Let's hit F5 again and see what happens
As you can see nothing happens, and the exception disapears. However I want to have a quick way to check if the hosting is correct. To do this, we will add another NuGet Microsoft.Owin.Diagnostics, which will allows to have a quick diagnostics
Next, we need to tell to our web application to use the diagnostics capabilities, calling the method UseTestPage() during the configuration phase
Let's hit F5 again, and open a browser and type our url on the address bar
Cool! Now we have an http listener which serves always this simple test page, greeting "Welcome to Katana". Now we need to add another NugGt, Microsoft.Owin.StaticFiles, which will allow us to serve our static files (Html, CSS, Javascript files, etc.). For some reason, this nuget is not being returned in the search result when using the window "Manage NuGet Package". So, we will have to use the Package Manager Console and use the command
Install-Package Microsoft.Owin.StaticFiles -Version 0.20-alpha-20220-88 -Pre
Now we need to configure our static files component to tell the path where the static files are. In my case I choose to create a folder webdir to be the static files container, and it will be located in the same directory of the executing assembly
Let's add an Index.html file to webdir folder and try to navigate to this page in the browser (do not forget to mark this file to be added to the output directory)
Hit F5 and browse to http://localhost:12345
Very good. Now we can serve static files. Half of our problem is solved, since an AngularJS application it's just a bunch of Html, javascript, CSS, and imagesfiles.
But if you remember, we need also to use WebApi, which is the way to return some data to the app. Let's add another NuGet, Microsoft.AspNet.WebApi.Owin, which will allow us to host WebApi controllers and provide a REST api on our application.
Now we need to configure the WebApi, telling the route pattern to use.
Basically we configured to use the route /api/{controller} tou our WebApi controllers. Let's add a simple HomeController with the Get method, returning a simple string.
Let's Hit F5 and browse to the url http://localhost:12345/api/home
The WebApi content-negotiation resulted in a json fle. Let's click Open to see the content
Bingo. Our application now handles WebApi.
Finally, to install this as a windows service, we just need to add a project installer
Compile in release mode, install the windows service (using installutil.exe) and you are ready to add your AngularJS application, which will be served by the windows service process, without the need of Internet Information Service (IIS). With this, now I can consider to build my configuration tool (to run on desktop) using AngularJS and WebApi.
You can download the full code in my github account.