During the Microsoft MVP Summit this year Microsoft showed off a very early implementation of a very light weight Owin Web host running on IIS, code named Helios. Owin is a somewhat recent HTTP hosting specification for .NET, that specifies a set of base interfaces required to create adapters that provide a common bootstrapping and configuration interface for Owin components, frameworks or 'middleware' as it's known (a crappy word to describe this if you ask me).

Full disclaimer: The Helios Host is currently a Microsoft prototype, and it's basically a proof of concept - which means it probably has been hacked together in a very short timeframe. But it allows us to get a glimpse of what a very low level Owin host inside of IIS might look like in the future and this is what this post is about.

The Helios host that was shown at the summit is an Owin implementation that sits directly on top of raw IIS, rather than on top of the ASP.NET HttpRuntime. The current IIS/ASP.NET Owin host used by SignalR and Web API and other middleware like the new Identity system, ride on top of the a System.Web Owin adapter that basically creates Owin semantics from ASP.NET's HttpRuntime components (WorkerRequest and Context).

Helios is more low level and this means you get the benfits of the hardened, highly performant and lifetime managed core IIS environment without the overhead of traditional ASP.NET - best of both worlds. While creating self-hosted applications with OWin is straight forward, building a reliable, secure and performant hosting environment is not, and hosting on IIS solves that problem at least in the medium term, until (if at all) Microsoft decides to reinvent IIS using a different architecture altogether (I'm sure they have to be thinking about this in light of Node.js's succes). Even then Helios can serve as an abstraction that makes it easier to hop to other server platforms.

So, Helios doesn't use System.Web and directly hooks into IIS's native interfaces to provide to base Owin interfaces and context semantics. It runs entirely outside of the stock ASP.NET Http Runtime environment, bypassing the module pipeline and default ASP.NET runtime processing. If you look at code executing at the end of an Owin request you won't see a reference to System.Web in the Call Stack.

In short, Helios is a very light-weight and short circuited version of a Web host bootstrapped on top of raw IIS. Keep in mind that although IIS and ASP.NET are closely tied together, the IIS core itself is a fairly lightweight and runs entirely in native code. ASP.NET interaction only kicks in if ASP.NET modules or handlers are installed and those are comparitively slow when compared to the native core and native modules.

Using Helios you can bypass this interweaving and instead host and run .NET directly on the much leaner IIS core. Think of it as self-hosting directly inside of IIS but without System.Web or the core of ASP.NET. Bottom line, it's very light weight and as you'll see in a minute, very fast.

Setting up Helios

Helios is based on Owin and Microsoft published a pre-release package that provides the Helios Owin IIS host. The package you want to install is:

Microsoft.Owin.Host.IIS

The steps to setting up a Helios project is:

  1. Create an ASP.NET Web Application in VS 2013
  2. Set the project to use .NET 4.5.1 (required!)
  3. Compile the project
  4. Remove all references besides System, System.Core, Microsoft.CSharp
  5. Use NuGet to add Microsoft.Owin.Host.IIS
    Install-Package Microsoft.Owin.Host.IIS -Pre
    Install-Package Microsoft.Owin.Diagnostics

Note: Make sure you have the latest version of NuGet installed and the solution you add to has NuGet Package Restore enabled if you're adding to an existing solution. The install failed for me when adding to an existing solution until I updated Nuget.exe in the solution with Nuget update -self.

When you're done you should now have a Helios ready project with only the System and OWin related assemblies in it. Note there's no reference to System.Web or any of its dependencies:

AssemblyRefs_thumb

Setting up the Startup Class

Once the host is set up, you now need to add a startup class that wires up the Owin startup behavior and middleware handlers that are responsible for processing requests.

The simplest thing you can do is:

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

[assembly: OwinStartup(typeof(HeliosSample.Startup))]

namespace HeliosSample
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseErrorPage();
            app.UseWelcomePage();        
        }        
    }
}

The assembly directive is required and the runtime hook needed for Owin to bootstrap your startup class code. In the class you implement a Configuration() method which is responsible for specifying the various middleware pieces that should fire in response to requests. Think of this like module/handler configuration and behavior configuration in ASP.NET Runtime terms.

When you run the site with:

http://localhost/HeliosSample/ or

http://localhost:123456/

you'll see a built-in welcome page that pops up. If an error occurs the UseErrorPage() handler spits out a stock error page that looks similar with some error info on it. To try out the error page remove the app.UseWelcomePage() call and basically let the request fall through.

Note: Looks like there's an internal bug in Helios at the moment in that it always returns a 500 error code, although responses are rendered just fine.

Updated: Got a note from Levi Broderick at Microsoft with a temporary workaround for this issue which involves a small middleware hook to set a specific flag. The fix is shown in the next code snippet.

Creating a manual Handler

If you actually want to do something useful with your new server, you'll need to hook up appropriate middleware that actually does some work. There are several Owin frameworks (Web API and SignalR for example) or various pieces of middleware (the Identity Authentication module for example) you can easily use, but before I show that, let's start by demonstrating how end point configuration works roughly by creating a manual code handler that acts as an endpoint.

The following code is a HelloWorld style page that writes out some text and echos back some environment variables:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        // Bug Workaround for 500 error
        app.Use((ctx, continuation) =>
        {
            ((Action)ctx.Environment["server.DisableResponseBuffering"])();
            return continuation();
        });

        app.UseErrorPage();
        //app.UseWelcomePage();            

        app.Run(async (context) =>  // IOWinContext
        {
            context.Response.StatusCode = 200; 
            context.Response.ContentType = "text/html";

            await context.Response.WriteAsync("Hello World. Time is: " + DateTime.Now.ToString());
            //return;
                
            string header = "<html><body><h1>Helios Vars</h1>";
            await context.Response.WriteAsync(header);

            foreach (KeyValuePair<string, object> keyvalue in context.Environment)
            {
                if (keyvalue.Value == null)
                    continue;

                string t = keyvalue.Key + ":  " + keyvalue.Value.ToString() + "<hr />\r\n";

                await context.Response.WriteAsync(t);
                //await Task.Delay(1000);  // no output buffering - text just goes
            }

            await context.Response.WriteAsync("</body></html>");
        });
    }
}

I replaced app.WelcomePage() with a manual code handler using app.Run() and removed app.WelcomePage() because it's an endpoint handler which terminates the pipeline - you can only have one handler that terminates the pipeline, so either app.WelcomePage() or app.Run() with my code above can run, but not both.

App.Run() receives a IOwinContext instance that provides a context object that gives access to the Owin Request and Response objects. These objects provide input and output semantics not unlike HttpRequest and HttpResponse in ASP.NET's runtime, but these are actually of interfaces of type IOwinRequest and IOwinResponse respectively which have much less functionality (currently at least) then the ASP.NET equivalents. As a breath of fresh air most of the Owin intrinsic objects are passed as interfaces so they are much more easily replaced and mockable for testing.

The actual 'handler' code is very low level - roughly what I would call the equivalent of an HttpHandler in the ASP.NET pipeline. To demonstrate the features I iterate over the environment variables that the context publishes and spit them out into the output stream.

A couple of interesting things here. First off note that I make the lambda function async, so it runs asynchronously. I then use async calls to Response.WriteAsync() to take advantage of the inherent asynchronousness of the OWin pipeline which should drastically improve scalability if applied to async capable IO operations (like database, file and network access etc.). This isn't going to be an issue in this simple example, but for longer running operations this easy async offloading will likely result in big scalability gains as it can free up IIS threads.

Secondly notice the commented code to await Task.Delay(1000) which as suggested delays for one second between writing each of the keys. You don't ever want to do this in a real app, but by doing this you can actually see that Helios, currently at least, is not buffering HTTP output. Rather as you make each call to Response.WriteAsync(), each string immediately renders to the HTML output displayed in the browser which is nice. If you recall ASP.NET buffers output by default, and even if you turn off buffering it still batches writes into chunks of some size before output is sent to the client. Here, since I'm not sending a content-length in my output IIS the browser can immediately display the content which is nice.

Adding Web API to the Pipeline

We've seen how to essentially hook into the pipeline at a low level. Handling a single request is interesting for seeing things work, but not very practical. Typically App.Run() or similar calls act as entry points to some sort of framework or service that handles requests. Microsoft has at least two prominent frameworks that can run on top of Owin in ASP.NET: Web API and SignalR. So let's look to see how to host Web API and access a controller as an example.

To start add the Web API Owin NuGet package from the package manager console:

Install-Package Microsoft.AspNet.WebApi.Owin

Hooking up basic Web API functionality is then straight forward:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        // Bug Workaround for 500 error
        app.Use((ctx, continuation) =>
        {
            ((Action)ctx.Environment["server.DisableResponseBuffering"])();
            return continuation();
        });

        app.UseErrorPage();
     
        // Configure Web API for self-host. 
        HttpConfiguration config = new HttpConfiguration();
        config.MapHttpAttributeRoutes();
        config.Formatters.Remove(config.Formatters.XmlFormatter);
        app.UseWebApi(config);            

        app.Run(async (context) =>  // IOWinContext
        {
            …
}); } }

Here I'm creating an HttpConfiguration() object and hook up the new Web API 2.0 Attribute Route mapping, so that I can create custom routes on a controller without having to set up global routes. Using the configuration here is no different than in an ASP.NET based Web API app - it's the same HttpConfiguration object and you can set all the same configuration options you can there.

I can then use the app.UseWebApi() extension method (from System.Web.Http) on the IAppBuilder instance to start up Web API. At this point Web API is ready to handle API requests. Because I'm going to use AttributeRouting I don't even need to preconfigure my routes.

Note that I can have both Web API and my original custom endpoint handler I created in the last example, because Web API only handles requests that are mapped to specific routes. Any requests that don't hit any of the API routes defined just fall through to my custom Run() handler. In other words the pipeline determines when and how requests are handled and whether they are handled and terminated or passed on.

In order to make Web API do something now, I have to add a controller and set a custom route on it. To do this I can create a new class like this:

public class TestController : ApiController
{
    [HttpGet]
    [Route("test/HelloWorld/{name?}")]
    public string HelloWorld(string name = null)
    {
        return "Hello cruel World, " + name + ". " + DateTime.Now.ToString();
    }

}

Hey what's life without HelloWorld, right? :-) So here's a test controller with a HelloWorld method that maps routes like:

http://localhost:12345/test/helloworld/rick

which simply echo's back a string with my name and time.

Performance

I really encourage you to create this sample and run it yourself. If you do and run it - even in debug mode - the first thing you'll notice how quickly it starts up. Even in debug mode and both in IIS Express and full IIS the start up is very, very quick compared to a even a simple full ASP.NET runtime application. It's very noticeable. Refreshing even the simple pages is so fast you wonder if anything changed - it's fast enough that you don't even see status bar in chrome. All subjective I suppose but it's definitely noticeable.

Last year I wrote a blog post regarding ASP.NET NoOp performance of various ASP.NET frameworks, where I checked various ASP.NET technologies and how they compare in terms of running dummy requests, which roughly measures 'runtime' startup cost to get to the processing code. To see how Helios fares in comparison, added this project and ran the Apache Bench tests in comparison.

It turns out that Helios is definitely faster, faster than a low level HttpHandler beating out the HttpHandler by well over a 20% margin. However, the more interesting thing was to compare hitting a Web API endpoint in both ASP.NET and Helios and here the performance difference shows Helios more than 30% more efficient, which is substantial.

Here's a typical result of what I got from my AB.exe loads with 20,000 requests with 50 simultaneous connections. Here's a result screen shot from the HTML page that is generated at the end of the test:

AbBench_thumb

The first request is Helios with just a string result (ie. the first example, minus the Environment looping) which is the same as the base "Hello world sample" in the other NoOp benchmarks. That one is roughly 12% faster. HeliosJson is the Web API hosted on Helios so this compares to the WebAPIJson result, that's more than 32% faster. This is really informal, though on my development machine with everything local. The variance range of load test results are about 2-4% roughly between fastest and slowest runs, but the differences between Helios and non-Helios speeds stay fairly constant. In this test I'm running 20,000 iterations with a load factor of 50 instances.

Any of these results are nothing to sneeze at. Even the slowest result of 3100 Web requests a second on a laptop when running a serialized JSON result is pretty freaking amazing when you think about it!!!

If you want you can play around with this yourself - I've updated the project on GitHub to include the Helios example I've discussed here:

So yes, there's a definite performance benefit for using Helios and Owin! Now to be fair, it's very true that Helios is basically a prototype that hasn't been hardened and has undergone all the necessary feature factoring - I can imagine that before this technology hits production lots of functionality will be added and that's bound to have some performance impact slowing things down, but still I suspect it will still be significantly faster getting to your user code.

The Helios example is an empty shell and nothing is configured on the pipeline, whereas in ASP.NET there are default modules that run. But that's the point - using Owin the default is to start with a blank slate and add things that you need, rather than as in ASP.NET where you have a mysterious hierarchical parent key somewhere that pulls in a module that you don't even know is running that has to be removed to optimize performance. With Owin you always start from scratch and only add the building blocks you need, so you don't pay a performance penalty for those components you don't need. You get to decide what performance price you want to pay - and that's the way it should be!

Memory and Loaded Libraries

The big deal of Helios though is that it removes a lot of internal cruft. When you run even an ASP.NET HttpHandler, you end up deeply nested inside of the ASP.NET stack. Looking at the Helios stack you also end up fairly deeply nested, but the amount of code actually running and loaded in terms of dependencies in the call stack is much less. The result is lower memory overhead.

To check this out I set up two separate AppPools and tested the Helios Web API example and the ASP.NET based Web API example, then added a couple of controller methods to each of the controllers like this (this is the one in the Helios controller):

[HttpGet]
[Route("test/WorkingSet")]
public string WorkingSet()
{
    return "Helios - Working set is: " + Process.GetCurrentProcess().WorkingSet.ToString("n0") + " bytes";
}

and another for the ASP.NET based version. I then hit those servers a few times to warm them up and then hit the pages below - the numbers start somewhat low, and slowly creep up a little until they stabilize.

The memory use result here is:

WorkingSet_thumb

ASP.NET uses more than 2.5 times more memory on startup just to get the runtime up. So Helios is definitely making a dent here.

This will be a lot less dramatic once you add other .NET components used by your application, but nevertheless those 70+ megs of memory come right off the top of the ApplicationPool launch and initial load. 

What's all mean?

It's easy to look at this and go - so what? Memory is cheap, and so is computer CPU horse power. I was talking with Filip (@filip_woj) on Thursday and we both were saying that there's so much horsepower available in server boxes today that neither one of us had the need to even scale out to multiple machines in a very long time. Remember those 3100+ requests a second - you can go a long way with that and if you're not the Facebook or Twitter of the day, chances are scalability is not super high on your list.

Still Resource Usage matters

But, these days with Cloud solutions where you have to pay for CPU cycles and memory, resource usage is getting more important again - especially if you are not self-hosting (as I and most of my customers are). For cloud based solutions like Azure or hosted ISP solutions the reduced footprint means less resource overhead which in turn means saved money and that money saved often translates into lower bills for the Cloud customer as well. Faster performance generally also means fewer CPU cycles are expended to perform the same task and again in compute payment environment that matters. It translates to less power used, less hardware required and on and on.

Asynchronous

The hosting core is also completely asynchronous, so in theory at least it should scale a lot better as it doesn't tie up IIS IO threads for the duration of requests, but rather delegates IO threads out to IO completion ports for efficient processing while the CPUs are free to go on to the next IIS connection (actually ASP.NET runtime has been doing this for some time behind the covers with the AsyncHttpHandler which all handlers delegate to even if they're not async) and Helios formalizes that async-ness explicitly.

It's a Core - nothing more

Because the actual hosting core is just that - a core that is small and light weight, rather than the whole of ASP.NET wrapped into a single assembly (System.Web) -  it should make it much easier to extend functionality without having to add to the core. For the ASP.NET team, and also us as developers this means it'll be much easier to extend IIS using pluggable and very focused and specialized components that can be loaded via NuGet. For the ASP.NET team this means that new features can be shipped much more easily and can simply be bin deployed without worry of breaking some obscure and unrelated part of a large runtime. Likewise for third parties it'll mean there will be much more opportunity to extend the platform.

Changing Web Platform

But it's not just about performance and resource usage. The ASP.NET platform was designed nearly 15 years ago, and things have changed. We build very different applications today than we did back then. In those days long transactional operations dominated Web servers and large HTML generation tasks dominated. Today we have many more, short and quick requests for things like AJAX and componentized rendering and we have things like WebSockets persisting connections for long periods of times. This is a re-imagination of the things that work very well with IIS and the Microsoft Web Platform and improving on those features and leaving behind some of the things that have a dragging effect on the platform - things that are no longer used or were not built optimally to begin with.

Simplify!

But maybe more importantly, this is a simplified IIS hosting stack for .NET that is smaller and much less interconnected. Fewer dependencies. It's more flexible and makes it a lot easier to plug in components at every level. It makes it easier to build small components that can be assembled into whole solutions rather than plugging a single massive System.Web assembly into an app that attempts to do everything. I think it'd be nice to have choices among many small components that potentially solve the same problem in different ways to address very specific scenarios, rather than have one generic solution that tries to solve all problems in one place. It's more flexible for the consumer, and much easier to build for the provider as they can focus and provide specialized functionality without worrying about every permutation under the sun.

What's in it for the Application Developer?

Friends, simplification is an important point and if you're on the sidelines wondering what all of this Owin, Helios and general redesign of ASP.NET has to do with getting your day to day job done - that is the real reason to be excited and interested in it. These modularizations of the stack will allow more innovation, flexibility and ultimately better tools that eventually will affect a better experience at the Application Developer level. Right now it may not seem to be related to you, and that's probably true, but it will take some time for the benefits to ripple all the way to application development level in the form of more agile and flexible components and tooling.

In order for this to have an effect and even reach the application level developer we need components that support Owin. This is plumbing stuff and application developers will see the benefits of this technology only in the higher level technologies that sit on top of it. Today this means WebAPI and SignalR and third party libraries like Nancy, ServiceStack etc. which can run ontop of OWin can take advantage of Helios already. However, the HTML based frameworks like ASP.NET MVC and WebForms currently cannot use this - and it'll likely take some time if and when MVC or and MVC like framework will come from Microsoft to run on OWin. I suspect it'll happen, but it might look a bit different than the current incarnation that runs on System.Web.

It's a Prototype but it's promising and it's showing Direction

Interesting things will come from these prototypes. They have the potential to shake up the status quo of ASP.NET that's been the rule for over 10 years now. And in my opinion at least I think it's exciting to see these changes, even if it will probably take a couple of years to play out into a new set of updated and more nimble frameworks. To me it seems an important step for Microsoft to stay relevant at a time when a lot of people are leaving the Microsoft world for other platforms whether for good or bad reasons. Technology has rarely been a problem with Microsoft - it's usually the culture, but these changes point at change in attitude toward more distributed and open ideas, including the fact that most of the development of these new tools happens openly with Open Source and public discussion, rather than behind closed doors.

We'll have interesting times ahead in the ASP.NET space…

Resources