ASP.NET Core - Middleware
In ASP.NET Core requests are handled via "request pipeline". Request pipeline receives HTTP request from browser,processes and manipulates them, and finally generates a response. The software components that makes up this request pipeline are termed as Middleware. Therefore, request pipeline is a sequence of middlewares. It is the middleware decision of either calling another middleware in the request pipeline or terminate the request pipeline by sending a response back to previous middleware.
Working of Middleware
Whenever HTTP request arrives at the application "Kestrel Web server (Host to ASP.NET Core Application)" receives it and creates the httpContext. This httpContext is then passed to first middleware in the request pipeline which processes the request. The passing of request between middlewares continues until last middleware appears. The last middleware terminates the pipeline by sending request back to previous middleware thereby giving a second chance to every middleware in the request pipeline to inspect request and modify the response on way back. Finally the response is received by the "Kestrel Web server" which in turn send response back to the client. The request pipeline terminates whenever any middleware does not send request to next middleware which is called short-circuiting the request pipeline. The process of short-circuiting may be desired in order to avoid unnecessary work. For example :- static file request is handled by the static file middleware after which
it can short circuit the request pipeline.
Configuration of Middleware
For using any middleware it needs to be added to the request pipeline. Middleware is added in Configure method of the startup class.
Following is the default Configure method of the startup class :-
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Run(async (context) =>
{
await context.Response.WriteAsync("<div> Hello World</div>");
});
}
IApplicationBuilder is used while dealing with a request. The Configure method receives the instance of IApplicationBuilder, using which our Middleware are registered.
There are four methods available to interact with a request.
- Use :- It adds a middleware to the request pipeline which may or may not call the next middleware in the pipeline.
- Run :- The terminating middleware is added by this method.
Example of Use and Run method
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//two arguments one is HttpContext and other is RequestDelegate(which calls next middleware)
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("<div> Middleware 1 is called </div>");
// await next.Invoke();
});
app.Run(async (context) =>
{
await context.Response.WriteAsync("<div> Middleware 2 is called </div>");
});
}
These two methods include inline middleware.
Output:-
Explanation: This is because middleware1 does not call middleware2 thereby request pipeline ends at middleware1. To call middleware2 invoke method of next middleware should be called whose reference is given in the constructor. In above code if line "await next.Invoke()" is uncommented following output is obtained.
Output :-
The above output is obtained since Middleware is executed in the same order in which they are added in the pipeline.
The order of addition of middleware components in the Configure method defines ordering in which they are invoked on requests. The ordering of middleware components is critical for security, performance, and functionality.
Example:-
public void Configure(IApplicationBuilder app)
{
app.UseExceptionHandler("/Home/Error"); // Called firstly in order to catch exceptions
// thrown in the following middleware.
app.UseStaticFiles(); // Return static files and short circuit the request
// pipeline.
app.UseIdentity(); // Authenticate before accessing secure resources.
app.UseMvcWithDefaultRoute(); // Adding MVC to the request pipeline.
}
- Map :- Map method is used for connecting a request path to another middleware.
- MapWhen :- It is similar to Map method except in this detailed condition can be specified using a HttpContext object.
Example of Map and MapWhen
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("<div> Middleware 1 is called </div>");
await next.Invoke();
});
app.Map("/TestMapRoute", HandleTestMapRoute);
app.MapWhen(delegate (HttpContext context)
{
return context.Request.Query.ContainsKey("culture");
}, HandleTestMapWhen);
app.Run(async (context) =>
{
await context.Response.WriteAsync("<div> Middleware 2 is called </div>");
});
}
private static void HandleTestMapRoute(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("<div> Middleware for when route is called </div>");
});
}
private static void HandleTestMapWhen(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("<div> Middleware for mapwhen route is called </div>");
});
}
Below table shows the requests and responses from http://localhost:64580 using the previous code:
http://localhost:64580/ |
Middleware 1 is called
Middleware 2 is called
|
http://localhost:64580/TestMapRoute |
Middleware 1 is called
Middleware for when route is called
|
http://localhost:64580/?culture |
Middleware 1 is called
Middleware for mapwhen route is called
|
Creation of Custom Middleware
To create a middleware custom class right click on .net core project and select “Add Item”, select an option "Middleware class" and name it "CustomCultureMiddleware" to add a middleware class template.
The above command causes creation of following CustomCultureMiddleware class.
// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
public class CustomCultureMiddleware
{
private readonly RequestDelegate _next;
public CustomCultureMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext httpContext)
{
var cultureinfo = httpContext.Request.Query["culture"];
if (!string.IsNullOrWhiteSpace(cultureinfo))
{
var culture = new CultureInfo(cultureinfo);
CultureInfo.CurrentCulture = culture;
CultureInfo.CurrentUICulture = culture;
}
// Call the next delegate/middleware in the pipeline
return this._next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class CustomCultureMiddlewareExtensions
{
public static IApplicationBuilder UseCustomCultureMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CustomCultureMiddleware>();
}
}
This class contains a non-static constructor with RequestDelegate parameter. This parameter is used for calling next middleware in the pipeline. This class also contains Invoke method that takes httpContext parameter and returns a Task. This method is called whenever a request arrives at the middleware. In above CustomCultureMiddleware we are setting current request culture from the query string.
In startup.cs file within configure method above created custom middleware is called.
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCustomCultureMiddleware();
app.Run(async (context) =>
{
await context.Response.WriteAsync($"Culture of current request is {CultureInfo.CurrentCulture.DisplayName}");
});
}
Running above code with url "http://localhost:64580/" without setting culture parameter display current culture of the browser.
Running above code with url "http://localhost:64580/?culture=en" displays following output.
0 Comment(s)