[ASP.NET Core MVC Pipeline] Middleware Pipeline

The ASP.NET Core MVC Pipeline
The ASP.NET Core MVC Pipeline
Middleware Pipeline
Middleware Pipeline

What is a Middleware?

So, what is a middleware in the context of the Core MVC Pipeline, and why should we care about it?

Middleware Pipeline
Middleware Pipeline
  • A middleware can execute successfully its function and still pass the request to next middleware, therefore allowing for more changes before sending the response.
  • The routing middleware is certainly an important one but he is not vital on the middleware pipeline. It is vital to the MVC Framework, but you could have a perfectly working application without the routing middleware.

Our first Middleware

The sequence of middleware is defined on the Configure method of the Startup.cs class.

public class Startup
{
// ... More Code

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseDeveloperExceptionPage(); // Exception Handling Page Middleware

app.UseStaticFiles(); // Static Files serving Middleware

app.UseMvcWithDefaultRoute(); // MVC Routing Middleware
}
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseDeveloperExceptionPage(); // Exception Handling Page Middleware

app.UseStaticFiles(); // Static Files serving Middleware

/* Custom Middleware Inline */
app.Use(async (context, next) =>
{
if (context.Request.Method == "GET")
await next();
else
await context.Response.WriteAsync("Invalid method");
});
/* End Custom Middleware Inline */

app.UseMvcWithDefaultRoute(); // MVC Routing Middleware
}

Order Matters

Keep it in mind, the order in which your middleware is set up inside the Configure method matters! It matters because this is the order in which they are going to be executed when a request is received. In our example our custom middleware would never be hit if the user requests an existing static resource (like an image, or a JS file) because the UseStaticFiles middleware would have handle the request and sent a response to the user shortcutting the request.

Before AND After the next Middleware

We can see in our example that the execution of the next middleware in the pipeline is represented by a call to the next() delegate, and that means that we can execute some logic before and after the next delegate execution.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseStaticFiles();

app.Use(async (context, next) =>
{
// Execute some BEFORE before calling the next middleware
await next();
// Execute some AFTER before calling the next middleware
});

app.UseMvcWithDefaultRoute();
}

Use, Run or Map

Every middleware must run using one those three methods that define a specific behavior for the middleware.

app.Use(async (context, next) => { 
// Our custom logic
if(something)
{
await next();
// More custom logic
}
else
{
// Next middleware is never called on this path
}
});
app.Map("/CustomPath", (appPath1) =>
{
appPath1.Use(async (context, next) =>
{
// Cuustom Middleware code for Path 1
await next();
});
});

app.Map("/AnotherCustomPath", (appPath2) =>
{
appPath2.Run(async (context) =>
{
// Custom Middleware code for Path 2
await context.Response.WriteAsync("Done");
});
});
app.MapWhen(context => context.Request.IsHttps, appContext =>
{
appContext.Use(async (context, next) =>
{
// Custom Logic
await next();
});
});

app.MapWhen(context => context.Request.Method == "GET", appContext =>
{
appContext.Run(async context =>
{
await context.Response.WriteAsync("Done!");
});
});

Creating our Custom Middleware

First of all we need to do is to create a new class and, to do that, we are going to follow some simple conventions. Our Middleware’s class and filename must end with the word ‘Middleware’:

public class CustomHeadersMiddleware
{
private readonly RequestDelegate next;

public CustomHeadersMiddleware(RequestDelegate next)
{
this.next = next;
}

public Task Invoke(HttpContext context)
{
return next(context);
}
}
  • The Middleware must have a Constructor that accepts one RequestDelegate
  • The Middleware must have a public Method that receives an HttpContext as parameter and returns a Task type.
public class CustomHeadersMiddleware
{
private readonly RequestDelegate next;

public CustomHeadersMiddleware(RequestDelegate next)
{
this.next = next;
}

public async Task Invoke(HttpContext context)
{
if (context.Request.Method == "GET")
{
context.Response.Headers.Add("AzureCoderBlog", DateTime.UtcNow.ToString());
await next(context);
}
else
{
await context.Response.WriteAsync("Method not Allowed");
}
}
}

Hookup with the Middleware Pipeline!

While this is a working code for a middleware we haven’t hooked this up to our pipeline. Let’s do this now. Back to our Startup.cs Class, in our configure method, we want our new middleware to be added like this:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseStaticFiles();

app.UseMiddleware<CustomHeadersMiddleware>();

app.UseMvcWithDefaultRoute();
}
public static class CustomHeadersMiddlewareExtensions
{
public static IApplicationBuilder UseCustomHeaders(this IApplicationBuilder app)
{
return app.UseMiddleware<CustomHeadersMiddleware>();
}
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseStaticFiles();

app.UseCustomHeaders();

app.UseMvcWithDefaultRoute();
}
Middleware Samples
Middleware Samples

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Lucas Araujo | Azure Coder

Lucas Araujo | Azure Coder

Software Development and everything that encircles it :)