Thoughts, Tips and Tricks on what I'm currently do for a living. Currently most of my spare time is spent on contributing to Akka.NET.

Wednesday, August 31, 2011

“Hello World” with OWIN (on Kayak)

A link to all code can be found at the end of this post.

When I started implementing an OWIN compatible web framework I couldn’t find any examples on how to get started with OWIN. Jef Claes has an example but this seems to be for an older draft of OWIN. So this post is about how to create a really simple OWIN web application in C#. It’s inspired by Jef Claes code and uses code from Benjamin van der Veen´s example.

Please Note! This post was written when OWIN was Draft 1.0, using Kayak 0.7.2 and Gate 0.1.4. Things might have changed since this post.

Set up the project

Start by creating a C# Console App.

Install the NuGet package Gate.Kayak. This will install the these packages too: Gate & Kayak.

Kayak is is an asynchronous HTTP server written in C#. Gate.Kayak brings OWIN support to Kayak. If you want to host your OWIN app in another environment use another gate like Gate.AspNet or Gate.Wcf.

Create the Kayak Web Server

In order to set up a Kayak web server, we need to tell Kayak three things: What endpoint to listen to; how to handle exceptions and shut downs; and how to handle the incoming requests.

Main() – Configuring and Starting the Server

In this example the Main method of the Console App configures the Kayak server and starts it.

static void Main(string[] args)
{
   //Create the endpoint for incoming requests to Kayak    
   var kayakEndPoint = new IPEndPoint(IPAddress.Any, 5500);
   Console.WriteLine("Listening on " + kayakEndPoint);

   //Start Kayak and call the method Startup.Configuration when starting
    //Let SchedulerDelegate handle exceptions and shut downs
   KayakGate.Start(new SchedulerDelegate(), kayakEndPoint, Startup.Configuration);
}

An endpoint on port 5500 is created. When Kayak is starting it will configure itself by calling the Startup.Configuration method (more on this below), and when stopped, or when an exception is thrown, SchedulerDelegate handles this.

SchedulerDelegate

The methods in SchedulerDelegate class is called when exceptions during Kayak´s event loop occurs and when Kayak is being stopped. We’ll just write messages to the Console.

public class SchedulerDelegate : ISchedulerDelegate
{
   public void OnException(IScheduler scheduler, Exception e)
   {
       // called whenever an exception occurs on Kayak's event loop.
       // this is good place for logging. here's a start:
       Console.WriteLine("Exception on scheduler");
       Console.Out.WriteStackTrace(e);
   }

   public void OnStop(IScheduler scheduler)
   {
       // called when Kayak's run loop is about to exit.
       // this is a good place for doing clean-up or other chores.
       Console.WriteLine("Scheduler is stopping.");
   }
}

Startup.Configuration

Next we need to tell Kayak what to do with incoming requests. The method Startup.Configuration is responsible for that and it will be called when Kayak is starting. In this example, we specified it explicitly in the Main method, but if you were to host the OWIN application on Asp.Net using Gate.AspNet this method will automatically be found and invoked (it’s a convention in Kayak). So creating class with the name Startup with a static method Configuration makes your application more easily portable to other Gate hosts.

public class Startup
{
   // called automatically when Kayak starts up.
   public static void Configuration(IAppBuilder builder)
   {
       // we'll create a very simple pipeline:
       var app = new HelloWorldOwinApp();
       builder.Run(Delegates.ToDelegate(app.ProcessRequest));
   }
}

First our OWIN application is instantiated and then Kayak is told to to let the app´s ProcessRequest method handle all incoming requests.

HelloWorldOwinApp

The primary interface in OWIN is the application delegate. An application delegate takes three parameters: an environment dictionary, a response callback, and an error callback. The HelloWorldOwinApp class exposes the method ProcessRequest that has the same signature as the application delegate specified in OWIN Draft 1.0 and this is where all the fun happens.

If the requested resource, i.e. the path, is the root, “/”, we return a Hello World html page. Otherwise a 404 page is returned.

public class HelloWorldOwinApp
{
   public void ProcessRequest(
        IDictionary<string, object> environment,
       Action<string, IDictionary<string, string>,
               Func<Func<ArraySegment<byte>, Action, bool>,
               Action<Exception>, Action, Action>> responseCallBack,
       Action<Exception> errorCallback)
   {
       var path = environment["owin.RequestPath"] as string;
       var responseHeaders = new Dictionary<string, string>();
       ArraySegment<byte> responseBody;
       string responseStatus;
       if (path == "/")
       {
           responseStatus = "200 OK";
           responseHeaders.Add("Content-Type", "text/html");
           responseBody = new ArraySegment<byte>(Encoding.UTF8.GetBytes((
                   "<!doctype html><html><head><meta charset=\"utf-8\">" +
                       "<title>Hello World</title></head>" +
                   "<body><strong>Hello world</strong></body>" +
                   "</html>")));
       }
       else
       {
           responseStatus = "404 Not Found";
           responseHeaders.Add("Content-Type", "text/html");
           responseBody = new ArraySegment<byte>(Encoding.UTF8.GetBytes((
                   "<!doctype html><html><head><meta charset=\"utf-8\">" +
                       "<title>404 Not Found</title></head>" +
                   "<body>The resource cannot be found.</body>" +
                   "</html>")));
       }
       responseCallBack(
           responseStatus,
           responseHeaders,
           (next, error, complete) =>   // This is the Body Delegate
           {
               next(responseBody, null);
               complete();
               return () => { };
           });
   }
}

The signature is hideous. The people behind OWIN are well aware of this, and considered interfaces in an assembly that all had to implement, but, thankfully, decided to go with using Funcs and Actions instead. This means that there is no OWIN.dll you have to reference, and therefor no versioning conflicts can occur.

Except from the signature, this method is pretty straightforward. We get the relative path from the environment dictionary. If it’s “/” we return a Hello World html page. Otherwise a 404 page is returned.

Returning the resource is a bit special. Instead of just returning some kind of object with headers, status and body content the responseCallBack is invoked. This is necessary for everything to be asynchronous. The callback has as three arguments: the response status; response headers; and a delegate (the next-error-complete-delegate) for retrieving the body content.

The delegate is called the Body Delegate and it is invoked by the host whenever it is ready to receive the body content. The signature of the delegate makes it possible to return chunks of the body. But to keep it simple we will return everything in one chunk, and that is what the next(responseBody, null) call does. responseBody is an ArraySegment (basically a byte array with information about which part of the array the consumer should use).

For simple applications, like this, you don’t have to understand how the Body delegate is intended to be used. Just copy-paste this example, and add the content to responseBody.

Say Hello!

Start the console app. In a browser navigate to http://localhost:5500. You should see a page with “Hello World” in bold. Now go to http://localhost:5500/NotThere and you’ll get a 404 page.

That’s it. Now you have everything you need to create a OWIN web application.

Code

The code can be found on github gist. Show all code.

No comments:

Post a Comment