AspNetCore Request Pipeline and Middlewares VS2017

AspNetCore, like its predecessors Katana and vNext, heavily rely on middleware. Lets consider middleware as a black boxed components filled with instructions. One of these instructions is to call the next middleware. If the next middleware is available to call, then it’s called on the call stack but if there isn’t control is given back to the previous middleware.

Request pipeline is a sequenced collection of middleware connected with each other more like a linked list of methods.

Pipeline

When a request is received its handed over to the first Middleware 1, this middleware executes the code and hand the request over to next Middleware 2. 

Note that middleware two has some code to execute before calling the next middleware as well as it has some code to execute after the next middleware is executed and control is returned to Middleware 2.

Middleware 3 is not linked to any other middleware further so the response object will be handed back to the Middleware 2. Since Middleware 2 has some code to execute, it will execute the rest of the code to may be manipulate the response and send the control back to the Middleware 1.

Middleware 1 has nothing to execute after the calling of Middleware 2, the response object is sent as it is without further modifications to the clients.

AspNetCore Middleware

middleware are components chained together to form the request pipeline.

Lets create a simple pipeline in an empty AspNetCore application. I created an empty AspNetCore application. Startup.cs class has following Configure() method.

public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World!");
    }
}

Pipeline can be created using app.Run(), app.Map(), app.Use(), app.UseMiddleware() methods. There may be other methods in the IApplicationBuilder interface but most of them are variant for these methods.

In the above code request is passed through only one middleware that just writes “Hello World!” on the response. Running application in IISExpress will print “Hello World!” on the browser.

Lets add another simple middleware to the request pipeline. app.Use() method is used to append middleware in the pipeline.

public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
    app.Use(async (context, next) => {
        await context.Response.WriteAsync("1st middleware");
        await next.Invoke();
    });

    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World!");
    }
}

The difference between app.Run() and app.Use() is that app.Run() short-circuit the pipeline. It means app.Run() doesn’t call next middleware, putting an end to the call stack.

Lets make another change to better understand and before checking the output.

public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
    app.Use(async (context, next) => {
        await context.Response.WriteAsync("1st middleware");
        await next.Invoke();
        await context.Response.WriteAsync("1st middleware ended");
    });

    app.Use(async (context, next) => {
        await context.Response.WriteAsync("2nd middleware");
        await next.Invoke();
    });

    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World!");
    }
}

In theory it should execute in the following order.

  1. 1st middleware prints “1st middleware” and invoke the second middleware. It will wait for the completion of execution from all subsequent middleware.
  2. 2nd middleware prints “2nd middleware” and invokes the next middleware.
  3. Third middleware is called with app.Run() method. Means it prints “Hello World!” but do  not invoke any further middleware.
  4. Control will move back to the 2nd middleware which has nothing further to perform any action and will be back to 1st middleware.
  5. First middleware prints “1st middleware ended”.

Following is the output on a browser.

Result

My middleware are simple so i used lambda expressions to create middlewares. I can also create middlewares in a separate class.

    public class TestMiddleware
    {
        private readonly RequestDelegate _next;
        public TestMiddleware(RequestDelegate next) {
            _next = next;
        }

        public Task Invoke(HttpContext context) {
            context.Response.WriteAsync("Test class middleware");
            return this._next(context);
        }
    }

The class implementation that can be called as a middleware should accept a RequestDelegate in the constructor. It should also have an invoke method which returns the RequestDelegate accepted in the constructor. Lets add this middleware in the pipeline.

public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
    app.Use(async (context, next) => {
        await context.Response.WriteAsync("1st middleware");
        await next.Invoke();
        await context.Response.WriteAsync("1st middleware ended");
    });

    app.Use(async (context, next) => {
        await context.Response.WriteAsync("2nd middleware");
        await next.Invoke();
    });

    app.UseMiddleware();

    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World!");
    }
}

app.UseMiddleware<TestMiddleware>() registers the middleware in the pipeline. The output with this configuration is as follows

Result2

having middleware makes AspNetCore extensible as well as maintainable. There are number of middleware provided by Microsoft. Open source market is also updating the code base on daily basis as middleware allow individual programmers to update their middlewares even in nightly builds and provide the updates to the consumers as fast as they can code.

 

Advertisements

2 thoughts on “AspNetCore Request Pipeline and Middlewares VS2017

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s