Understanding ASP.NET - Part Two - Building An Owin Pipeline

Introduction

If you are new to Owin and Katana and haven’t read the part1 of this series, I strongly recommend you to go back and read that part as well in order to have a better understanding of where we started from and where we are heading to.

  1. Understanding ASP.NET -Part1- Owin and Katana.

But if you already have a good understanding of Owin and project Katana, then you are ready to go from here.

In this part, we will build a simple Owin pipeline from scratch. We will take a look on how we can host our Owin pipeline into ASP.NET application and how we can plug-in different middlewares into the pipeline.

Building Owin Pipeline Step by Step

We’ll build a simple Katana based Owin pipeline with two middlewares in it, that can handle incoming HTTP requests and return response to the requesting client.

As we have discussed in part1, Owin comes with a pipeline of things called middlewares and a middleware is self-contained block code that can handle request, perform processing and can return response as well independent of host and other parts of the application. Now, let’s create the pipeline from an empty ASP.NET MVC project.

Step 1 Creating an empty ASP.NET project

We’ll create the pipeline from scratch so that we can have better understanding of what is required, what NuGet packages we need to install, and how much code it takes to build a simple Owin pipeline with project Katana.

Create a new ASP.Net project with empty template selected, and make sure to not to select any folder structure. Let’s just be simple for now.

ASP.NET

When you select an empty template, you do actually get an empty project with some necessary assembly references and a web.config file.

ASP.NET

At this point, web.config file only contains information about the runtime, target framework, and compiler configuration for both C# and VB which we will not be touching any way.

ASP.NET

Step 2 Getting necessary NuGet Packages

Now, we’ll install some NuGet packages that we need to host Owin app in ASP.Net application.

Basically, we require three packages to host and run an Owin app inside ASP.NET.

  1. Owin
  2. Microsoft.Owin (Depends on Owin)
  3. Microsoft.Owin.Host.SystemWeb (Depends on Microsoft.Owin)

We will only install the host package which is Microsoft.Owin.Host.SystemWeb, and the NuGet Package Manager will resolve the dependencies for us and will install the other packages as well.

Open Package Manager Console window and type the following command.

ASP.NET

NuGet will install the packages, will reference the DLLs and will add packages.config file in solution with some information about the packages we installed.

ASP.NET

The actual Owin implementation of project Katana is inside the Microsoft.Owin package.

Step 3 Creating an Entry Point

Entry point is a point from where application starts and executes rest of the code. When we are working with Katana, we should have a class named Startup.cs in root directory of project.

ASP.NET

Inside the class, we will create an actual entry point by creating a public method named Configuration with the following syntax and this is the default convention. 

  1. public class Startup  
  2.     {  
  3.         /*IAppBuilder object is used to plugin middlewares  
  4.         into pipeline*/  
  5.         public void Configuration(IAppBuilder app)  
  6.         {  
  7.              
  8.         }  
  9.     }    

You can name the method whatever you want and put it wherever you want, but if you do so, then you will have to add some configuration in web.config file to tell the runtime where the entry point is located. 

  1. <appSettings>  
  2.     <add key="owin:AppStartup" value="OwinPipeline.Startup"/>  
  3. </appSettings>  

You can also specify the entry with an assembly level attribute.

  1. [assembly: OwinStartup(typeof(OwinPipeline.Startup))]  

Step 4 Creating our first Middleware

Now, we have an entry point. Let’s create a simple middleware that will return a peaceful message to client. To plug in a middleware into Owin pipeline, we’ll use the “use” method of IAppBuilder object that takes a delegate as parameter. 

  1. public void Configuration(IAppBuilder app)  
  2.         {  
  3.             app.Use(async (context, nextMiddleWare) => {  
  4.   
  5.             });  
  6.         }   

The first argument in lambda expression is of type IOwinContext and the second one is another delegate.

ASP.NET

Syntax may be confusing because we were expecting a middleware that will take a dictionary object as an argument and will return a task object.

As we have discussed earlier in the first part, Katana is not by the book implementation of Owin specification; instead people at Microsoft implemented it in their own way for ease of use to average developer. Now, let me explain the confusion here.

  • IOwinContext: is actually a wrapper around environment dictionary that have defined some common task to perform on dictionary object.
  • Func<Task>: is a delegate that actually returns a task when it’s called.

This is how Microsoft implemented Owin. Now, we have our middleware ready but the one thing left is returning a peaceful message to client. This is how we’ll do that. 

  1. app.Use(async (context, nextMiddleWare) => {  
  2.                 await context.Response.WriteAsync("Peace be on world.");  
  3.             });   

WriteAsync method on Response property of context object is actually writing message to response stream stored in environment dictionary object under the key “Owin.ResponseBody”.

Now, start the app without debugger attached, and you will see your message coming back from Server.

ASP.NET

Congratulations, our first middleware is up and running.

Step 5 Building a pipeline

A pipeline with one middleware is not much of a pipeline. Now, let’s create another middleware that will log information about incoming request path and response status code. Having two middlewares in pipeline will give us a nice opportunity to experience request and response flow in pipeline.

  1. app.Use(async (context, nextMiddleWare) =>  
  2.          {  
  3.              Trace.WriteLine("Request: " + context.Request.Path);  
  4.                
  5. await nextMiddleWare();//will forward request to next middleware  
  6.   
  7.              /*at this point responce headers will be sent client  
  8.              /and response body is about to sent*/  
  9.              Trace.WriteLine("Responce Status Code:" + context.Response.StatusCode);  
  10.          });   

Now, run the app with debugger attached and open the output window to see logged messages.

ASP.NET

We have a fully working OWIN pipeline with two middlewares and the goal of our part 2 is completed.

Thank you for coming this far with me. Stay tuned for the next part. In next part, we’ll go further in creating middlewares and plugging middlewares in pipeline with extension methods on IAppBuilder.

Startup.cs 

  1. using System;  
  2. using System.Threading.Tasks;  
  3. using Microsoft.Owin;  
  4. using Owin;  
  5. using System.Diagnostics;  
  6.   
  7. [assembly: OwinStartup(typeof(OwinPipeline.Startup))]  
  8.   
  9. namespace OwinPipeline  
  10. {  
  11.     public class Startup  
  12.     {  
  13.         /*IAppBuilder object is used to plugin middlewares  
  14.         to build a pipeline*/  
  15.         public void Configuration(IAppBuilder app)  
  16.         {  
  17.             app.Use(async (context, nextMiddleWare) =>  
  18.             {  
  19.                 Debug.WriteLine("Request: " + context.Request.Path);  
  20.                   
  21.   await nextMiddleWare();//will forward request to next middleware  
  22.   
  23.                 /*at this point responce headers will be sent client  
  24.                 /and response body is about to sent*/  
  25.                 Debug.WriteLine("Responce Status Code:" + context.Response.StatusCode);  
  26.             });  
  27.   
  28.             app.Use(async (context, nextMiddleWare) =>  
  29.             {  
  30.                 await context.Response.WriteAsync("Peace be on world.");  
  31.             });  
  32.         }  
  33.     }  
  34. }