Run, Use and OWIN Middleware Chaining

Microsoft.Owin NuGet package contains AppBuilderUseExtensions class that provides extension methods for chaining middlewares in OWIN pipeline.

The source code for this post can be found at https://github.com/DmitryZinchenko/blogRunUseAndChaining

Run or Use?

  • Run – inserts into the OWIN pipeline a middleware which does not have a next middleware reference
  • Use – inserts into the OWIN pipeline a middleware which has a next middleware reference

The type of the delegate for the Run method is

Func<IOwinContext, Task>

and the type of the delegate for the Use method is

Func<IOwinContext, Func<Task> /* next middleware */, Task>

Let’s see how they work.

// listing #1
public void Configuration(IAppBuilder app)
{
    Func<IOwinContext, Task> middleware = async (IOwinContext context) =>
    {
        await context.Response.WriteAsync(" [middleware] ");
    };

    app.Run(middleware);
}

As you can see, the middleware gets a reference to the OWIN context object only and there is no way to invoke the next middleware in the pipeline.

If you run the application and navigate your browser to http://localhost:5000/owin you will see

b003-img001

// listing #2
public void Configuration(IAppBuilder app)
{
    Func<IOwinContext, Func<Task>, Task> middleware = async (IOwinContext context, Func<Task> next) =>
    {
        await context.Response.WriteAsync(" [middleware - before ]");
        await next.Invoke();
        await context.Response.WriteAsync(" [middleware - after] ");
    };

    app.Use<UseHandlerMiddleware>(middleware);
}

This middleware gets references to both – OWIN context and the next middleware objects. Notice that this middleware does something before and after invoking the next middleware.

b003-img002

OWIN Middleware Chaining – The Wrong Way

OWIN Middlewares are responsible for invoking the next middleware in the pipeline or short circuiting the request by creating the response and returning the Task.

// listing #3
public void Configuration(IAppBuilder app)
{
    Func<IOwinContext, Func<Task>, Task> middleware1 = async (IOwinContext context, Func<Task> next) =>
    {
        await context.Response.WriteAsync(" [middleware1 - before ]");
        await next.Invoke();
        await context.Response.WriteAsync(" [middleware1 - after] ");
    };

    Func<IOwinContext, Task> middleware2 = async (IOwinContext context) =>
    {
        await context.Response.WriteAsync(" [middleware2] ");
    };

    app.Run(middleware2);
    app.Use<UseHandlerMiddleware>(middleware1);
}

Notice, that we first called Run method and then Use, thus adding both middlewares to the pipeline. The order of invoking middlewares in the pipeline matches the order in which they have been added to it.

Even though both middlewares have been added to the pipeline, middleware1 will never be invoked because middleware2 does not have a reference to the next middleware.

b003-img003

OWIN Middleware Chaining – The Right Way

// listing #4
public void Configuration(IAppBuilder app)
{
    Func<IOwinContext, Func<Task>, Task> middleware1 = async (IOwinContext context, Func<Task> next) =>
    {
        await context.Response.WriteAsync(" [middleware1 - before ]");
        await next.Invoke();
        await context.Response.WriteAsync(" [middleware1 - after] ");
    };

    Func<IOwinContext, Task> middleware2 = async (IOwinContext context) =>
    {
        await context.Response.WriteAsync(" [middleware2] ");
    };

    app.Use<UseHandlerMiddleware>(middleware1);
    app.Run(middleware2);
}

This time, we first added middleware1 to the pipeline and then middleware2. Since middleware1 has reference to the next middleware – it is able to invoke it.

b003-img004

One More

Let’s add one more middleware and prove that the first one added to the pipeline is able to perform some work before it invokes the second one, then the second one is able to do something before it invokes the third one. After the third one finishes its work, the second is able to do something else and then – the first one.

// listing #5
public void Configuration(IAppBuilder app)
{
    Func<IOwinContext, Func<Task>, Task> middleware1 = async (IOwinContext context, Func<Task> next) =>
    {
        await context.Response.WriteAsync(" [middleware1 - before ]");
        await next.Invoke();
        await context.Response.WriteAsync(" [middleware1 - after] ");
    };

    Func<IOwinContext, Func<Task>, Task> middleware2 = async (IOwinContext context, Func<Task> next) =>
    {
        await context.Response.WriteAsync(" [middleware2 - before ]");
        await next.Invoke();
        await context.Response.WriteAsync(" [middleware2 - after] ");
    };

    Func<IOwinContext, Task> middleware3 = async (IOwinContext context) =>
    {
        await context.Response.WriteAsync(" [middleware3] ");
    };

    app.Use<UseHandlerMiddleware>(middleware1);
    app.Use<UseHandlerMiddleware>(middleware2);
    app.Run(middleware3);
}

b003-img005

Invoke or Short Circuit

As you remember, if a middleware has a reference to the next one – it can chose to either invoke it or not. Let’s modify our code and see what happens. Let’s assume that the consumer of our web application needs to provide API key if they want to use some service.

// listing #6
public void Configuration(IAppBuilder app)
{
    Func<IOwinContext, Func<Task>, Task> middleware1 = async (IOwinContext context, Func<Task> next) =>
    {
        await context.Response.WriteAsync(" [middleware1 - before ]");
        await next.Invoke();
        await context.Response.WriteAsync(" [middleware1 - after] ");
    };

    Func<IOwinContext, Func<Task>, Task> middleware2 = async (IOwinContext context, Func<Task> next) =>
    {
        await context.Response.WriteAsync(" [middleware2 - before ]");

        if ((context.Request.Query["apiKey"] ?? string.Empty).Equals("123"))
        {
            await next.Invoke();
        }

        await context.Response.WriteAsync(" [middleware2 - after] ");
    };

    Func<IOwinContext, Task> middleware3 = async (IOwinContext context) =>
    {
        await context.Response.WriteAsync(" [middleware3] ");
    };

    app.Use<UseHandlerMiddleware>(middleware1);
    app.Use<UseHandlerMiddleware>(middleware2);
    app.Run(middleware3);
}

Let’s first make a request without providing API key by navigating to http://localhost:5000/owin . As expected, middleware2 short circuited the pipeline and did not invoke middleware3.

b003-img006

This time – let’s provide API key – http://localhost:5000/owin?apiKey=123 . As expected, middleware2 was able to verify the API key and invoke the next middleware.

b003-img007

You Say “Tomato”, I Say “Tomato”

You might want to chose a different coding style and provide inline delegates for Run and Use methods. Ah… Potato/potato…

// listing #7
public void Configuration(IAppBuilder app)
{
    app.Use(async (IOwinContext context, Func<Task> next) =>
    {
        await context.Response.WriteAsync(" [middleware1 - before ]");
        await next.Invoke();
        await context.Response.WriteAsync(" [middleware1 - after] ");
    });

    app.Use(async (IOwinContext context, Func<Task> next) =>
    {
        await context.Response.WriteAsync(" [middleware2 - before ]");

        if ((context.Request.Query["apiKey"] ?? string.Empty).Equals("123"))
        {
            await next.Invoke();
        }

        await context.Response.WriteAsync(" [middleware2 - after] ");
    });

    app.Run(async (IOwinContext context) =>
    {
        await context.Response.WriteAsync(" [middleware3] ");
    });
}

Summary

  • Use, Use, Run not Run, Use, Use
  • Invoke or Short Circuit
Run, Use and OWIN Middleware Chaining