Owin, Katana and getting started

Posted by: Glavs Blog, on 04 Apr 2013 | View original | Bookmarked: 0 time(s)

Introduction

This article describes an emerging open source specification, referred to as Owin An Open Web Interface for .Net, what it is, and how this might be beneficial to the .Net technology stack. It will also provide a brief, concise look at how to get started with Owin and related technologies. In my initial investigations with Owin and how to play with it, I found lots of conflicting documentation and unclear ways of how to make it work and why. This article is an attempt to better articulate those steps so that you may save yourself lots of time and come to a clearer understanding in a much shorter time than I did.

Note: The code for this article can be download from here.

First, What is it?

Just in case you are not aware, a community driven project referred to as Owin is really gaining traction. Owin is a simple specification that describes how components in a HTTP pipeline should communicate. The details of what is in the communication between components is specific to each component, however there are some common elements to each. Owin itself is not a technology, just a specification.

I am going to gloss over many details here in order to remain concise, but at its very core, Owin describes 2 main components. First,Owin describes the following interface:

public interface IAppBuilder
{
    IDictionary<string, object> Properties { get; }

    object Build(Type returnType);
    IAppBuilder New();
    IAppBuilder Use(object middleware, params object[] args);
}

The IAppBuilder interface which acts as the glue or host to bring any registered Owin compatible libraries/modules together. Owin also describes the following function signature:

Func<IDictionary<string, object>,Task>

This is a function that accepts a simple dictionary of objects, keyed by a string identifier. The function itself returns a task. The object in the dictionary in this instance will vary depending on what the key is referring to.

More often, you will see it referenced like this:

using AppFunc = Func<IDictionary<string, object>,Task>

An actual implementation might look like this:

public Task Invoke(IDictionary<string, object> environment) 
{ 
   var someObject = environment[some.key] as SomeObject; 
   // etc 
}

This is essentially how the environment or information about the HTTP context is passed around. Looking at the environment argument of this method, you could interrogate it as follows:

var httpRequestPath = environment[owin.RequestPath] as string; 
Console.WriteLine(Your Path is: [{0}],httpRequestPath);

if a HttpRequest was being made to http://localhost:8080/Content/Main.css then the output would be:

Your Path is [/Content/Main.css]

So what? I can do that now without Owin.

Okay so it may not look ground breaking, but this is the core of Owin and key to understanding what it offers. Since we have a basic understanding of the how, I am going to jump to what it currently offers as a result of supporting this mechanism. With support of this simple mechanism, I can now write isolated components that deal with specific parts of functionality related to Http requests. I can then chain them together to build capabilities of my Http server. Internet Information Server does not need to get a look in. You can literally chain together Owin components to form a pipeline of only the necessary features you want. In addition, the components I write do not have to have specific references to any particular pipeline component, and yet can still take advantage of any Owin compatible component.

Basically you can build or use a custom host, then you can insert whatever custom modules into the Http request processing pipeline. Owin provides the specification for writing those modules that make it easy to insert into the chain.

Internet Information Services comes with a plethora of pipeline and request handlers, management functionality, knobs, dials and features that make a comprehensive web server. However many people want a lean, cut down web server with only the features they want. This provides a much leaner pipeline that can provide great performance, in addition to only providing the feature set you want, meaning a smaller surface area which can be beneficial from a complexity and sometimes a security perspective.

Quit yer jibba jabba fool, show me some code  MrT1

Yes yes, I will, but first, a diagram illustrating the previous paragraph. As already mentioned, Owin is just a specification of what interface to expose and how to work with that interface.In order for modules written to the Owin spec to be functional, they must exist in a host. So at a conceptual level, Owin compared to Internet Information Server looks like this:

slide1

Since we have an empty Owin host, we can programmatically add Owin compatible modules based on only what our needs are as illustrated below:

slide2

The diagram above shows an Owin host with 3 modules registered to be used, Static files,  Authentication and SignalR.

(Note: SignalR is a popular real-time web messaging/connection library and has been written as an Owin compatible module)

Are we there yet?

Ok, so lets finally write an Owin compatible module or library.

  1. Within Visual Studio, Create a new blank solution.
  2. Add a new class library project to it.
  3. Install the Owin nuget package using:
    Install-Package Owin
    (via the package manager console in Visual Studio or right click on the project in Visual Studio and select Manage Nuget Packages)
  4. Add a new class, lets call it TestLogger and paste in the following code:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AppFunc = Func<IDictionary<string, object>, Task>;
    public class TestLogger
    {
        private readonly AppFunc _next;
        public TestLogger(AppFunc next)
        {
            if (next == null)
            {
                throw new ArgumentNullException("next");
            }
            _next = next;
        }
        public Task Invoke(IDictionary<string, object> environment)
        {
            System.Diagnostics.Trace.WriteLine(string.Format("Hitting TestLogger, path: {0}", environment["owin.RequestPath"]));
            return _next(environment);
        }
    }

That is actually all you need to write an Owin compatible library. Strictly speaking, you dont need the reference to the Owin nuget package but we will make use of that in the next part. All this module does is write out the contents of the request path to the trace output for each request that comes in. All we need to do is examine the environment that is provided to us through the environment variable.

However, we have a module but nothing to host it in and no way to tell it to be included as part of a web server pipeline. We need an Owin capable host that loads our module and houses the running code. We also need to programmatically configure that host to include our module. Much like Internet Information Server acts as the host for most web apps in .Net..

So, we are going to add a web project to our solution which will act as the entry point, allowing us to configure a module for use in the web request pipeline.

  1. Within Visual Studio, add a new empty MVC project (I used MVC4) to your current solution.
  2. You need to reference at least the Owin assemblies. In addition, we are going to reference the Owin HttpListener written by Microsoft to act as the actual Http server in our Owin pipeline. To do this:
    Install the Owin nuget package and the Microsoft.Owin.HttpListener package using:
    Install-Package Owin
    Install-Package Microsoft.Owin.Host.HttpListener -Pre

    (via the package manager console in Visual Studio or right click on the project in Visual Studio and select Manage Nuget Packages. Note that the Microsoft.Owin.HttpListener package is pre-release so we need include the pre option.)
    After installing those packages, you should see the appropriate references in your project as shown in the screen grab below: proj-refs
  3. Add a new class to this MVC project called Startup
  4. Paste in the following code:
public class Startup
{
    // Invoked once at startup to configure your application.
    public void Configuration(IAppBuilder builder)
    {
        builder.Use(typeof(TestLogger));
    }
}

Here you can see we are using an instance of IAppBuilder passed into our configuration method to tell the host to Use our custom pipeline component, often referred to as Middleware in Owin speak.

Owin components use conventions for easy configuration, so when the Owin host starts up and loads our assemblies, it looks for the Startup class, and also a Configuration method which accepts an IAppBuilder instance, and calls that, providing the instance.

The final piece of the puzzle

Ok, we have our custom pipeline component, our middleware, and we have an entry point where we can build or configure our pipeline. We need a host process to load these assemblies and invoke them with the requisite information.

This is where Project Katana comes in. Katana is a Microsoft written generic Owin host. You can go grab the source of this project, compile and run it, but it is easier to just install it so you can call it from the command line. By far, the easiest way to do this is to install a tool called Chocolatey which is like a Nuget package installer but for windows binaries.

(Side Note: Chocolately is an awesome tool. If you get nothing else from this post, just use Chocolately to install some software and keep it up to date. It is easy to use and has a heap of applications supported.)

To install Chocolotey, run the following from a command line (literally copy and paste into a command line/console window):
@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('http://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%systemdrive%\chocolatey\bin

Once its installed, from the command line, simply type:
cinst Katana pre

And Katana will be magically installed. Now opening up a command line/console window and typing Katana will load and run the Katana application, which is our Microsoft written Owin host. Nothing will get loaded because we havent specified anything, but that is what is next.

We have written our custom Owin component, we have created our web application entry point used to configure our Owin pipeline and we have installed our host application, Katana, to glue it all together. So lets see in action.

First we need to tell our web project to NOT automatically use the current page when starting up. Rather, we want it to startup the Katana host, and tell Katana to use our assemblies. To do this:

  • Open up the properties of the web project in your solution and select the Web section. You should see a screen similar to the one shown below:.

WebProjectKatanaStartupOptions

For clarification, the things you need to enter are:

Ensure the Start External Program is selected and enter the full path to the Katana executable. I installed to the default location using Chocolately so mine is set at:

C:\Chocolatey\lib\Katana.0.20-alpha-20220-88\tools\Katana.exe

Set the command line arguments to:

-p8080 v

This represent the port number of 8080 and enabling verbose mode

Enter the working directory where your web project is located. In my case it was:

D:\Glav.Owin.Middleware\Glav.Owin.Consumer.Test.BasicWebConsumer

  • Now hit F5 to run the app. You should see a console application launched which looks similar to the one below:

running-katana

Now remember, the only component we have injected into the Owin pipeline is our own custom logging component. Since we have included the Microsoft.Owin.Host.HttpListener package into our project, that assembly also gets included in the output. When Katana executes, if no specific Http server is defined, it will automatically look for the Microsoft.Owin.Host.HttpListener assembly and use that.

  • Again, we only have our logging component installed, so if we load a browser, a navigate to http://localhost:8080 , we wont see a web page but the console should show the logging output of our custom component as in the screen shot below:

browsing-to-katana

 

All that work, for that?

Yes, but now we have everything in place to easily add other components in the pipeline. In addition, now you should have a reasonable understanding of the various pieces at play.  Remember, we have created a custom web server that only does exactly what we want it to.So conceptually, what we have created looks roughly like the following:

custom-katana-pipeline

Now lets create another component but I dont want to create another project for that.

Add the following method block to your Startup class in the web project in your solution:

// Invoked once per request.
public Task Invoke(IDictionary<string, object> environment)
{
   var responseBytes = System.Text.ASCIIEncoding.UTF8.GetBytes(
            string.Format("Serviced request on {0} at {1}",DateTime.Now.ToLongDateString(), DateTime.Now.ToLongTimeString()));
    Stream responseStream = (Stream)environment["owin.ResponseBody"];
    IDictionary<string, string[]> responseHeaders =
        (IDictionary<string, string[]>)environment["owin.ResponseHeaders"];
    responseHeaders["Content-Length"] = new string[] { responseBytes.Length.ToString(CultureInfo.InvariantCulture) };
    responseHeaders["Content-Type"] = new string[] { "text/plain" };
    return responseStream.WriteAsync(responseBytes, 0, responseBytes.Length);
}

Then add this line of code as the last line in the Configuration method within the Startup class.

builder.Use(new Func<AppFunc, AppFunc>(ignoredNextApp => (AppFunc)Invoke));

Now, hit F5 to run your app, and browser to http://localhost:8080

You should see a response in the browser similar to the screen grab shown below:

browsing-to-katana2

That code we added in the Invoke method, did the following:

  • Created a simple text response as a byte array.
  • Grabbed the response body stream and the response headers object from the environment variable using standard Owin defined key names.
  • Set the response headers according to the response itself.
  • Wrote the bytes to the response stream.

In order to use the code in the Invoke method, we needed to tell our pipeline to use it. This was achieved in the Configuration method via the line:

builder.Use(new Func<AppFunc, AppFunc>(ignoredNextApp => (AppFunc)Invoke));

This simply injected the delegate for our Invoke function into the pipeline. So now our comceptual pipeline looks like this:

final-pipeline

All without any real dependencies and in a relatively small amount of code.

And you made it

After all that, you can finally see how composable and modular the Owin concepts and architecture are. There are quite a few Owin compatible middleware modules out there such as SignalR, FubuMVC, NancyFx to name a few. These can be added to your pipeline and you then have the power that each brings at your disposal.

This is just the beginning. Imagine being able to easily build a custom web server with only the capabilities you need. An open, composable and modular world with no lock in. Sounds good to me. Hopefully the Owin concepts and goals are a little clearer now.

Remember, the code for this article can be downloaded from here.

Category: C# | Other Posts: View all posts by this blogger | Report as irrelevant | View bloggers stats | Views: 880 | Hits: 13

Similar Posts

  • Getting Started with OWIN and Katana more
  • Getting Started with OWIN and Katana more
  • Getting started with Owin and Katana more
  • Getting started with Owin and Katana more
  • Getting Started With OWIN, Katana, and VS2013 more
  • Owin, Katana and getting started more
  • LINQ in Action, the book is available as an early access edition more
  • My life as a web developer more

News Categories

.NET | Agile | Ajax | Architecture | ASP.NET | BizTalk | C# | Certification | Data | DataGrid | DataSet | Debugger | DotNetNuke | Events | GridView | IIS | Indigo | JavaScript | Mobile | Mono | Patterns and Practices | Performance | Podcast | Refactor | Regex | Security | Sharepoint | Silverlight | Smart Client Applications | Software | SQL | VB.NET | Visual Studio | W3 | WCF | WinFx | WPF | WSE | XAML | XLinq | XML | XSD