Tuesday, 15 July 2014

OWIN middleware-Asp.net integrated Pipeline extensions in Katana

OWIN Middleware components (OMC) to that of an HttpModule in the ASP.NET world, an OMC must be registered to the correct pre-defined pipeline event. In this article we’ll see how to create a middleware and register it with the pipeline event. Also default stage for the middleware execution in the pipeline. So let’s get started:

1. Create an empty Asp.net website.
clip_image002
2. Install the Microsoft.Owin.Host.SystemWeb Nuget package. You can either use the Nuget package manager UI from visual studio or directly run the below command in the Nuget package manager console:

Install-package Microsoft.Owin.Host.SystemWeb

This command will install the package library and other dependencies which includes “Owin”, Microsoft.Owin”. Note that the package Microsoft.Owin.Host.SystemWeb is support for System.Web in Owin.

3. Create a Startup class and here you can configure the startup of the server e.g. registering custom pipelines for stages, we’ll talk about about pipeline stages in later posts. Also host server will be supporting full debugging with in visual studio. Let’s just create a simple server startup configuration.

Startup.cs

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Run(context =>
            {
                context.Response.ContentType = "text/plain";
                return context.Response.WriteAsync("Hello Katana World!!!");
            });
    }
}

Run the server with F5. The host will be running on localhost:55666 port showing output like this.
clip_image003

As a default behaviour since we are using the SystemWeb the server will be serving the content using the Asp.net pipeline which in fact is IIS server. Now let’s now use the IIS server and use a little lighter host server to run our webapplication.

That was the simplest example of create an Asp.net IIS hosted application. Let’s do something interesting to understand the abstraction and flexibility between the server and application.

Let’s create a sample startup configuration that will display the information about the browser agent by reading the request header. Just update the code in the Configuration method of Startup class.

Startup.cs


/// <summary>
/// Implements the startup behavior for the host server.
/// </summary>
public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Run(context =>
        {
            context.Response.ContentType = "text/plain";
            return context.Response.WriteAsync(this.GetUserAgentInfo(context));
        });
    }
 
    private string GetUserAgentInfo(IOwinContext context)
    {
        return context.Request.Headers.Get("User-Agent");
    }
}

So I get the information about the User Agent for different browser:

Visual studio Inbuilt browser
clip_image005
Google chrome
clip_image007
Internet Explorer 11
clip_image008
This was simple isn’t it, let’s take a little dive with in and create some Middleware to interpret the request and response. We can create owin middleware implementation by two ways.
1. Creating a separate class for each Middleware for pipeline.
2. Using the Func delegate template and use it with in the Startup class.

First let’s create a BasicMiddleware to use in the pipeline. Also let’s add some code to see when this Middleware will be going to execute. Here’s the complete code for the class. In this class we’re adding a user item in the response header. That’s it.

BasicOwinMiddleWare.cs



public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Run(context =>
            {
                context.Response.ContentType = "text/plain";
                return context.Response.WriteAsync("Hello Katana World!!!");
            });
    }
}


Startup.cs


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Owin;
using System.Collections.Generic;
 
namespace Katana.HelloWorldServer
{
    using AppFunc = Func<IDictionary<string, object>, Task>;
    using Microsoft.Owin;
 
    // Note the Web.Config owin:AutomaticAppStartup setting that is used to direct all requests to your OWIN application.
    // Alternatively you can specify routes in the global.asax file.
    public class Startup
    {
        // Invoked once at startup to configure your application.
        public void Configuration(IAppBuilder builder)
        {
            // Custom middleware in separate class.
            builder.Use<BasicOwinMiddleWare>();
 
            // Middleware created with in startup class.
            builder.Use(new Func<AppFunc, AppFunc>(ignoredNextApp => (AppFunc)Invoke));
        }
 
        // Invoked once per request.
        public Task Invoke(IDictionary<string, object> environment)
        {
            string responseText = "Hello World";
 
            // writing response header asynchronously
            byte[] responseBytes = Encoding.UTF8.GetBytes(responseText);
 
            // See http://owin.org/spec/owin-1.0.0.html for standard environment keys.
            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);
        }
    }
}
(Snippet taken from: Katana samples)

Let’s run the server by hitting F5 again and see what happens.
Output:
clip_image009
As you can see the new item in the Response header is captured. Now let’s look at the stage of the pipeline as we did some tracing to get the stage when the response header was updated.
clip_image010
So Now we know the default stage to execute the Owin middleware is PreExecuteRequestHandler event. But here comes the interesting fact, You can customize this stage by using the StageMarker.

We’ll discuss this in our next post, How to run the middleware during various Asp.net pipeline stage events? Also, how to use a custom OWIN self-hosting process to host the web application? Don’t miss it.

References:
http://www.asp.net/aspnet/overview/owin-and-katana
http://www.asp.net/aspnet/overview/owin-and-katana/an-overview-of-project-katana
http://owin.org/spec/owin-1.0.0.html

No comments:

Post a Comment