CodeDigest.Com Logo
Featured:

Understanding and Creating OWIN Middlewares - Part 1

Tagged as: Asp.Net Asp.Net Core OWIN Posted By

In my previous article, What is OWIN? A Beginners Guide we learned the basics of OWIN and the benefits it brings to building web application in Asp.Net frameworks. We have also learnt to build a very simple application using Project Katana and different ways to deploy OWIN application in the next article Creating Our First OWIN Based Application. These articles helped us to understand what IAppBuilder interface is and how the Owin host tries to find the Startup class and bootstrap the application.  In this article, let’s understand the OWIN middleware components, their usages, and different ways of building middleware components.

What is a Middleware component?

A middleware is a component that runs during request processing in an OWIN based application. These middleware components are generally added into the application by calling IAppBuilder.Use() method from the Startup class.

Features of Middleware

  1. Each application can add multiple middlewares to form an OWIN middleware pipeline for request processing similar to HttpModules in classic Asp.Net applications.

  2. The middleware components runs in the same order it is added in the Startup class.

  3. A component can handle the incoming request and pass it to the next component in the pipeline.

  4. A component can break this pipeline and return the response without calling the next middleware during request processing.

A middleware component is constructed with the same syntax that of Application delegate or AppFunc delegate signature.

 

Func<IDictionary<string, object>, Task>

 

or

 

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

Func<AppFunc, Task>

 

 

Adding Middlewares into Owin Pipeline

The following syntax is used to add a middleware to add it into OWIN pipeline.

 

Func<in AppFunc, out AppFunc>

 

So, a middleware component take the next middleware component to call as an argument and returns an AppFunc.

The IAppbuilder has 4 methods to add a middleware into OWIN pipeline. One in Owin.dll and another 3 as extension methods in Microsoft.Owin.dll

Owin.dll

namespace Owin

{

    public interface IAppBuilder

    {

//Removed for brevity

        IAppBuilder Use(object middleware, params object[] args);

    }

}

 

 

Microsoft.Owin.dll

namespace Owin

{

    public static class AppBuilderUseExtensions

    {

        public static void Run(this IAppBuilder app, Func<Microsoft.Owin.IOwinContext, System.Threading.Tasks.Task> handler);

        public static IAppBuilder Use(this IAppBuilder app, Func<Microsoft.Owin.IOwinContext, Func<System.Threading.Tasks.Task>, System.Threading.Tasks.Task> handler);

        public static IAppBuilder Use<T>(this IAppBuilder app, params object[] args);

    }

}

 

 

Let’s use these 4 methods to build and register Owin middleware into the request pipeline. We will first create an empty Asp.Net web application project in visual studio for this.

  1. Open Visual Studio 2015(2012 or 2013).

  2. File > New > Project > Select Asp.Net Empty Web Application.

Now, let’s include the Katana packages. Since we intend to do this sample in an Asp.Net web application, we need to add Microsoft.Owin.Host.SystemWeb Nuget package. To do this, Open Solution Explorer, Right Click project node and select “Manage Nuget Package..”. Search for the package Microsoft.Owin.Host.SystemWeb and Click Install. This will install the Microsoft.Owin.Host.SystemWeb package and it’s dependent packages Microsoft.Owin and Owin.

  1. Now, let’s include a Startup class. Right click project node and select Add> Class… Name it as Startup.cs and Click OK.

Note – Visual Studio 2013 and 2015 include a new OWIN Startup Class template under Add > Add New Item.. You can use it if you have your project created in these versions.

  1. Add Configuration(IAppBuilder app) method and decorate the namespace with [OwinStartup] attribute. The final code looks like below,

 

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

namespace OwinMiddlewareDemo

{

    public class Startup

    {

        public void Configuration(IAppBuilder app)

        {

        }

     }

}

 

Include Owin and Microsoft.Owin namespace under using statements section at top.

Let’s also add a Default.aspx page into the solution and a display message “From Asp.Net WebForm!!!” from the page.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="OwinMiddlewareDemo.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">

    <title></title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

    <h1>From Asp.Net WebForm!!!</h1>

    </div>

    </form>

</body>

</html>

 

 

Let’s use IAppBuilder.Use(object middleware, params object[] args) method from Owin.dll to build a very simple Middleware to greet the user. The IAppBuilder.Use() method takes a middleware implementation object and optional data arguments for middleware. The object middleware can be a delegate reference to a middleware implementation method or inline middleware implementation. The implementation should honor the owin middleware syntax to add into the pipeline Func<in AppFunc, out AppFunc>

Inline Middleware

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

namespace OwinMiddlewareDemo

{   

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

    public class Startup

    {

        public void Configuration(IAppBuilder app)

        {         

 

            app.Use(new Func<AppFunc, AppFunc>(next => (async context =>

            {

                using (var writer = new StreamWriter(context["owin.ResponseBody"] as Stream))

                {

                    await writer.WriteAsync("<h1>MW1: Hello from inline Method middleware!</h1>");

                }

                await next.Invoke(context);

            })));

          

        }

      

    }

}

 

As we know, the Owin host(SystemWeb) will inject the environment dictionary (IDictionary<string, object>) with all header values into the middleware parameter “context” in the above Lambda expression. It then writes a greeting message into to the response and calls the next middleware.

Click F5 to run the project, you can see the output like below,

Middleware as Method Implementation

Let’s implement the same in a method instead of writing it as inline method. Add the below function under the Startup class.

 

public AppFunc MyMiddleWare(AppFunc next)

        {

            AppFunc appFunc = async (IDictionary<string, object> environment) =>

            {

                var response = environment["owin.ResponseBody"] as Stream;

                using (var writer = new StreamWriter(response))

                {

                    await writer.WriteAsync("<h2>MW2: Hello from Explicit Method middleware!</h2>");

                }

                await next.Invoke(environment);

            };

            return appFunc;

        }

 

 

As you can see, it implements the delegate signature Func<AppFunc,AppFunc>

To register this middleware,

 

var middleware = new Func<AppFunc, AppFunc>(MyMiddleWare);

app.Use(middleware);

 

 

When executed, we will all the 3 greeting messages in the browser.

Middleware Implemented as a Class

Include a class file named DemoMiddleware.cs into your solution. The class file implementation will take the next middleware in the pipeline as constructor argument. See the code below,

 

namespace OwinMiddlewareDemo

{

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

 

    public class DemoMiddleware

    {

        AppFunc _next;

        public DemoMiddleware(AppFunc next)

        {

            _next = next;

        }

        public async Task Invoke(IDictionary<string, object> environment)

        {

            using (var writer = new StreamWriter(environment["owin.ResponseBody"] as Stream))

            {

                await writer.WriteAsync("<h3>MW3: Hello from Middleware class method!</h3>");

            }

            await _next.Invoke(environment);

        }

    }

}

 

We will the IAppBuilder.Use<T>() extension method to register this middleware.

 

app.Use<DemoMiddleware>();

 

 

When executed, we will see the output as below,

 

Adding Middleware as Extension method to IAppBuilder

This is another way to add your custom middleware into Owin pipeline. When we create a custom middleware, it is good to expose the middleware registration as an extension method to IAppBuilder for better readability. To do this, add a new class into you project called OwinExtensions.  The extension method to add the above class type middleware is,

 

public static class OwinExtensions

    {

        public static void UseDemoMiddleware(this IAppBuilder app)

        {

            app.Use<DemoMiddleware>();

        }

    }

 

 

So, the startup code can be changed to,

 

app.UseDemoMiddleware();

 

 

Adding Middlewares Using Strongly Typed Environment Dictionary

All the above middleware methods used the raw environment dictionary to process the result. The Katana library expose the environment dictionary as a strongly typed OwinContext object when we use the extension method IAppBuilder.Use(Func<Microsoft.Owin.IOwinContext, Func<System.Threading.Tasks.Task>, System.Threading.Tasks.Task> handler) to register the middleware in an elegant way. The below simple middleware adds the greeting message by accessing the Response object as opposed to using environment dictionary directly.

 

  app.Use(async (Context, next) =>

            {

                await Context.Response.WriteAsync("<h4>MW4: Hello from inline Method middleware using OwinContext!</h4>");

                await next.Invoke();

            });

 

 

Output below,

 

Adding Middleware With No Next Middleware

There is an extension method IAppBuilder.Run() that adds a middleware with no next middleware to call. So, adding a middleware using this method will end the OWIN pipeline. Let’s add this middleware registration at the end in the Startup class.

 

app.Run(context =>

            {

                return context.Response.WriteAsync("<h5>MW5: My First Owin Application Ended!</h5>");

            }); 

 

 

On execution, the above middleware have aborted the pipeline and the output form a webform Default.aspx is not seen.

 

Middleware that explicitly ending the pipeline without calling Next Middleware

As I said before, a middleware can break the pipeline and return a response to client if needed. For example, assume there is a middleware responsible for authentication. The middleware can return a 401 unauthorized error if there is a request without credentials and it need not call next middleware in the pipeline.

To demonstrate this, let’s build a simple middleware that can block request made from Chrome browser alone. Code below,

 

app.Use(async (Context, next) =>

            {

                var b = HttpContext.Current.Request.Browser.Browser;

                if (b == "Chrome")

                {

                    await Context.Response.WriteAsync("<h1>Chrome Browser Access not allowed!!</h1>");

                }

                else

                {

                    await next.Invoke();

                }

            });   

 

 

The above middleware will return a message “Chrome Browser Access not allowed!!” if the application is accessed via chrome and will not call the next the middleware in the pipeline.

Output below,

Request from any other browsers will be executed as usual.

 

The final Startup class with all middleware code is,

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

namespace OwinMiddlewareDemo

{   

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

    public class Startup

    {

        public void Configuration(IAppBuilder app)

        {

            app.Use(async (Context, next) =>

            {

                var b = HttpContext.Current.Request.Browser.Browser;

                if (b == "Chrome")

                {

                    await Context.Response.WriteAsync("<h1>Chrome Browser Access not allowed!!</h1>");

                }

                else

                {

                    await next.Invoke();

                }

            });

 

 

            app.Use(new Func<AppFunc, AppFunc>(next => (async context =>

            {

                using (var writer = new StreamWriter(context["owin.ResponseBody"] as Stream))

                {

                    await writer.WriteAsync("<h1>MW1: Hello from inline Method middleware!</h1>");

                }

                await next.Invoke(context);

            })));

 

            var middleware = new Func<AppFunc, AppFunc>(MyMiddleWare);

            app.Use(middleware);

 

            //app.Use<DemoMiddleware>();

            app.UseDemoMiddleware();

 

            app.Use(async (Context, next) =>

            {

                await Context.Response.WriteAsync("<h4>MW4: Hello from inline Method middleware using OwinContext!</h4>");

                await next.Invoke();

            });

 

            app.Run(context =>

            {

                return context.Response.WriteAsync("<h5>MW5: My First Owin Application Ended!</h5>");

            });        

 

        }

 

        public AppFunc MyMiddleWare(AppFunc next)

        {

            AppFunc appFunc = async (IDictionary<string, object> environment) =>

            {

                var response = environment["owin.ResponseBody"] as Stream;

                using (var writer = new StreamWriter(response))

                {

                    await writer.WriteAsync("<h2>MW2: Hello from Explicit Method middleware!</h2>");

                }

                await next.Invoke(environment);

            };

            return appFunc;

        }

    }

}

 

 

Note – This article series is just for learning purpose, there are many changes in the next version of Asp.Net called Asp.Net Core that takes all these implementation to next level based on the feedbacks from Project Katana. To simply put, Asp.Net Core still use these OWIN concepts but with a new implementation. You can say the Asp.Net Core pipeline is evolved from OWIN and Katana Implementation. You call middleware as Asp.Net Core middleware and not OWIN middleware. The IAppBuilder interface was replaced IApplicationBuilder, it uses RequestDelegate and HttpContext(not the one in System.Web) for building middleware, we will learn more about this in an Asp.Net Core article. The basics are still same and reading this article will help you understand the basics and the Katana’s evolution until Asp.Net Core.

Download the source and see it in action.

In Part 2, we will see how these middlewares work along HttpApplication object (Global.asax) events when the application is hosted in IIS.



Feedback

Comments