In Part 1 of this article series, we have understood the basics of Middleware and constructing middlewares in different ways. Though, OWIN is introduced to remove the application dependency with webserver (IIS), we still use IIS for hosting our Asp.Net applications in Windows environments. In this article, let’s see how to control when a middleware component should run along the Global.asax events.
By default, all middleware components added into the Startup class run during the PreRequestHandlerExecute event of HttpApplication.
To demonstrate this, let’s use the sample project we built in the part 1 of this article. Refer Part 1 to know more.
We will add a Global.asax file into the project. To do this, right click project in Solution Explorer, Click Add> Global Application Class. This will add a new Global.asax file into your project.
Note - If you didn’t find Global Application Class file menu then click “Add New Item..” you will find the Global Application Class in the add new item dialogue.
To know, when an event is executing we will add simple text on the Global.asax event to print the event name. See below,
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.Write("Global.asax: <i>Application BeginRequest Event!!</i><br>");
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.Write("Global.asax: <i>Application AuthenticateRequest Event!!</i><br>");
}
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.Write("Global.asax: <i>Application PostAuthenticate Request Event!!</i><br>");
}
protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
HttpContext.Current.Response.Write("Global.asax: <i>Application PreRequestHandlerExecute Request Event!!</i><br>");
}
protected void Application_Error(object sender, EventArgs e)
{
}
protected void Application_End(object sender, EventArgs e)
{
}
protected void Application_EndRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.Write("Global.asax: <i>Application EndRequest Event!!</i>");
}
}
Startup method code we build in last part for reference,
public void Configuration(IAppBuilder app)
{
app.Use(async (Context, next) =>
{
var b = HttpContext.Current.Request.Browser.Browser;
if (b == "Chrome")
{
await Context.Response.WriteAsync("<h1>Chrome Browser Access not allowed!!</h1>");
}
else
{
await next.Invoke();
}
});
app.Use(new Func<AppFunc, AppFunc>(next => (async context =>
{
using (var writer = new StreamWriter(context["owin.ResponseBody"] as Stream))
{
await writer.WriteAsync("<h1>MW1: Hello from inline Method middleware!</h1>");
}
await next.Invoke(context);
})));
var middleware = new Func<AppFunc, AppFunc>(MyMiddleWare);
app.Use(middleware);
//app.Use<DemoMiddleware>();
app.UseDemoMiddleware();
app.Use(async (Context, next) =>
{
await Context.Response.WriteAsync("<h4>MW4: Hello from inline Method middleware using OwinContext!</h4>");
await next.Invoke();
});
//app.Run(context =>
//{
// return context.Response.WriteAsync("<h5>MW5: My First Owin Application Ended!</h5>");
//});
}
Let’s run the application straight away to see when the middleware components we added are getting called.
The output clearly says all the middlewares are executed during Application_PreRequestHandlerExecute or PreRequestHandlerExecute event.
Make Middleware to Execute at Particular HttpApplication Object Event
The Microsoft.Owin.Extensions namespace has an extension method for IAppBuilder called UseStageMarker() to make middleware to run during an application event. This extension takes the Application event name as argument and make the middleware to run at that time of execution. To mark the stage, there is an enum that defines different stages of events in HttpApplication object.
namespace Owin
{
// Summary:
// An ordered list of known Asp.Net integrated pipeline stages. More details
// on the ASP.NET integrated pipeline can be found at http://msdn.microsoft.com/en-us/library/system.web.httpapplication.aspx
public enum PipelineStage
{
// Summary:
// Corresponds to the AuthenticateRequest stage of the ASP.NET integrated pipeline.
Authenticate = 0,
//
// Summary:
// Corresponds to the PostAuthenticateRequest stage of the ASP.NET integrated
// pipeline.
PostAuthenticate = 1,
//
// Summary:
// Corresponds to the AuthorizeRequest stage of the ASP.NET integrated pipeline.
Authorize = 2,
//
// Summary:
// Corresponds to the PostAuthorizeRequest stage of the ASP.NET integrated pipeline.
PostAuthorize = 3,
//
// Summary:
// Corresponds to the ResolveRequestCache stage of the ASP.NET integrated pipeline.
ResolveCache = 4,
//
// Summary:
// Corresponds to the PostResolveRequestCache stage of the ASP.NET integrated
// pipeline.
PostResolveCache = 5,
//
// Summary:
// Corresponds to the MapRequestHandler stage of the ASP.NET integrated pipeline.
MapHandler = 6,
//
// Summary:
// Corresponds to the PostMapRequestHandler stage of the ASP.NET integrated
// pipeline.
PostMapHandler = 7,
//
// Summary:
// Corresponds to the AcquireRequestState stage of the ASP.NET integrated pipeline.
AcquireState = 8,
//
// Summary:
// Corresponds to the PostAcquireRequestState stage of the ASP.NET integrated
// pipeline.
PostAcquireState = 9,
//
// Summary:
// Corresponds to the PreRequestHandlerExecute stage of the ASP.NET integrated
// pipeline.
PreHandlerExecute = 10,
}
}
To make a middleware to run during particular stage, we need to call the IAppBuilder.UseStageMarker(PipelineStage) after the middleware registration. For example, to make first 3 registered middlewares to run during Application_PostAuthenticateRequest event call IAppBuilder.UseStageMarker(PipelineStage.PostAuthenticate) after third middleware registration. Startup code below,
public void Configuration(IAppBuilder app)
{
app.Use(async (Context, next) =>
{
var b = HttpContext.Current.Request.Browser.Browser;
if (b == "Chrome")
{
await Context.Response.WriteAsync("<h1>Chrome Browser Access not allowed!!</h1>");
}
else
{
await next.Invoke();
}
});
app.Use(new Func<AppFunc, AppFunc>(next => (async context =>
{
using (var writer = new StreamWriter(context["owin.ResponseBody"] as Stream))
{
await writer.WriteAsync("<h1>MW1: Hello from inline Method middleware!</h1>");
}
await next.Invoke(context);
})));
var middleware = new Func<AppFunc, AppFunc>(MyMiddleWare);
app.Use(middleware);
app.UseStageMarker(PipelineStage.PostAuthenticate);
//Removed for brevity
}
When executed you can see the first 2 middlewares running during PostAuthenticate event (The first middleware checks only if the browser is Chrome, so no output though it runs)
The order of the pipeline stage has to be maintained when calling with UseStageMarker() method. For example, if you set PipelineStage.Authenticate stage marker after setting PipelineStage.PostAuthenticate stage then all the middlewares that are set to run until the earliest(PipelineStage.Authenticate) will run during that stage. The below code will run all the 4 middlewares during Authenticate stage since as per order Authenticate runs earlier than PostAuthenticate.
public void Configuration(IAppBuilder app)
{
//1st middleware reg
//2st middleware reg
app.UseStageMarker(PipelineStage.PostAuthenticate);
//3rd middleware reg
//4th middleware reg
app.UseStageMarker(PipelineStage.Authenticate);
}
Note – This article series is just for learning purpose, there are many changes in the next version of Asp.Net called Asp.Net Core that takes all these implementation to next level based on the feedbacks from Project Katana. To simply put, Asp.Net Core still use these OWIN concepts but with a new implementation. You can say the Asp.Net Core pipeline is evolved from OWIN and Katana Implementation. You call middleware as Asp.Net Core middleware and not OWIN middleware. The IAppBuilder interface was replaced IApplicationBuilder, it uses RequestDelegate and HttpContext(not the one in System.Web) for building middleware, we will learn more about this in an Asp.Net Core article. The basics are still same and reading this article will help you understand the basics and the Katana’s evolution until Asp.Net Core.
Download the source and see it in action.