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