Introduction
It’s more transparent to hook middleware in ASP.NET 5 application compared to prior versions. We can use Run, Map and Use extension method to hook any middleware in between HTTP pipeline. In this example, we will understand the difference among them with an example.
Run Extension
The nature of Run
extension is to short circuit the HTTP pipeline immediately. It is a shorthand way of adding middleware to the pipeline that does not call any other middleware which is next to it and immediately return HTTP response. So, it’s recommended to use Run
extension to hook middleware at last in HTTP pipeline. Let’s see how Run
behaves in action.
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
app.Run(async context =>
{
await context.Response.WriteAsync("Return From Run.");
});
app.Run(async context => {
await context.Response.WriteAsync("This is second Run.");
});
}
Here, we hook two Run
functions next to next and while running, we are getting only response from first Run
.
That implies the first run has short circuit the HTTP request and sends response from itself without forwarding to next middleware.
Use Extension
In case of Use
extension, there is a chance to pass next invoker, so that HTTP request will be transferred to the next
middleware after execution of current Use
if there next
invoker is present. In this example, we have attached next
invoker with Use
extension, so that HTTP call will get transferred to next
middleware even we tried to return:
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
app.Use(next=> async context =>
{
await context.Response.WriteAsync("Return From Use.");
await next.Invoke(context);
});
app.Run(async context => {
await context.Response.WriteAsync("This is from Run.");
});
}
HTTP response within Use
extension. Here is the output of the above code fragment.
We are seeing that both string
s from Use
and Run
have printed as output. Here, we should notice that we are forwarding the HTTP request to next
level by adding the following line.
await next.Invoke(context);
Otherwise, Use
extension will not escalate HTTP request and will behave as Run
Extension method.
app.Use(next=> async context =>
{
await context.Response.WriteAsync("Return From Use.");
});
Once we remove the next.Invoker()
, we are getting output only from Use
Extension.
Map Extension
Map extensions are used as convention for branching the pipeline. We can hook delegate to Map
extension to push it to HTTP pipeline. Map
simply accepts a path and a function that configures a separate middleware pipeline. In this example, we will hook one middleware/delegate to HTTP pipeline using Map
extension.
private static void MyDelegate(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Returning from Map");
});
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
app.Map("/MyDelegate", MyDelegate);
}
In Map
extension, we have hooked MyDelegate delegate
with “/MyDelegate” path. So, when user will perform any HTTP call to the same path, the delegate
function will get triggered.
The message has returned from delegate
function. One fact we should notice that, Map
takes delegate
and within delegate
, it allows to use both Run
and Use
depending on the requirement. MapWhen
Extension supports path-based mapping, the MapWhen
method supports predicate-based middleware branching, allowing separate pipeline to be constructed in a flexible way. In this example, we have mapped middleware execution with the presence of query string “q
” in URL.
private static void HandleQuery(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Return from HandleQuery");
});
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
app.MapWhen(context => {
return context.Request.Query.ContainsKey("q");
}, HandleQuery);
app.Run(async context =>
{
await context.Response.WriteAsync("From Run extension");
});
}
This type of branching is very useful when we have a separate handler to handle a certain request. For example, in some scenarios, we may want to bypass AJAX call to some handler like this:
private void HandleAJAX(IApplicationBuilder app)
{
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
app.MapWhen(ctx =>
ctx.Request.Headers.Get("X-Requested-With") == "XMLHttpRequest", HandleAJAX);
}
Here, we are checking for “X-Request-With
” header in the current HTTP request. If the header is present, then the request is AJAX request and for that HandleAJAX
handler will take care of.
Summary
Middleware are a well known feature in ASP.NET which was incepted in form of HTTP Handler and HTTP module in the early Web Forms days followed by Delegating handler and Middleware (MVC6) in MVC framework. In this tip, we have learned to use Run
, Use
, Map
and MapWhen
extension method to hook middleware in ASP.NET 5/MVC6 HTTP pipeline. Those methods are ready to accept custom middleware too. Developers can easily create their own middleware to inject additional functionality in HTTP pipeline.