Deep dive into ASP.NET Core Middleware

facebooktwittergoogle_plusredditpinterestlinkedinmail

Deep Dive Into ASP.NET Core Middleware

I’m very excited to demonstrate the power of ASP.NET core Middleware which is the first stage of ASP.NET Core request life cycle. There are some significant changes in brand new ASP.NET core application compared to the request life cycle of the previous versions. This article gives you a better understanding on ASP.NET Middleware and demonstrates the capabilities to create a custom middleware.

What is ASP.NET core Middleware ?

Middleware is the series of components that forms the application request pipeline. These components are also responsible for handling the incoming request and generating appropriate response either directly or the help of the framework like MVC. ASP.NET core Middleware provides the feature like routing, session, CORS, Authentication, Caching. You can write and configure many middleware components to your apps. Consider the following examples.

Middleware

If you are requesting for a static file (Eg site.css), the static file middleware would respond and serve the static file as the response. In this case, the other two middleware (Authentication and routing) would not invoke. Same way if you are requesting a controller action then static middleware would not handle this, but it will send the request to the authentication middleware. Authentication middleware will check the authentication and pass to routing middleware to respond.

Configure the ASP.NET Core Middleware

There are 2 main classes involved in this process, that are Statup.cs and Program.cs class. Program.cs class is the entry point of the application and Startup.cs class defines a configure() method, used to register middleware.

Program.CS Class

 public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>() // To configure Middleware
                .UseApplicationInsights()
                .Build();
 
            host.Run();
        }
    }

Startup.CS Class

public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }
 
        public IConfigurationRoot Configuration { get; }
 
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc();
        }
 
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();
 
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseBrowserLink();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
 
            app.UseStaticFiles();
 
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }

There are 2 methods in starup.cs class, that are ConfigureServices() and Configure(). ConfigureServices() does exactly it sounds like. It is used to configure services that will be used by the application. Cofigure() method establishes the core HTTP pipeline by registering the middleware components. Here you can see some default helper methods like UseStaticFile() , UseMVC etc internally register the components into the middleware.

There are 3 methods ( Run, Use and Map) to configure middleware in ASP.NET Core.

  • Run – Generate a response and short cricute the request
  • Use – Perform logic and send request to next component
  • Map – Conditionally send the request to other middleware

Building a simple ASP.NET Core Middleware

Sample Middleware with Run()

Delete everything from Configure() method and add the following simple Run().

  public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            app.Run(async context =>
            {
                await context.Response.WriteAsync("This is my response");
            });
 
        }

The preceding code will handle all the request and respond with the text.

Configure Middleware With Run

Run() is used to end the pipeline and generally creates a response which means this component would not forward the request to later middleware even if you added more after.

Sample Middleware with Use() and Run()

In the following example, we have both Use() and Run() method. Here if your request path contains word “myuse” then Use() method respond with a text as we configured (“response to my use” ). Otherwise the else block has a invoke (next.Invoke()) method to pass the request to the next component. Here we will get the response from Run() component ( response will be “This is my response”)

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            app.Use(async (context, next) =>
            {
                if (context.Request.Path.Value.Contains("myuse"))
                {
                    await context.Response.WriteAsync("response to my use");
                }
                else
                {
                    Debug.WriteLine("Execute before Run");
                    await next.Invoke();
                    Debug.WriteLine("Execute after Run");
                }
 
            });
 
            app.Run(async context =>
            {
                await context.Response.WriteAsync("This is my response");
            });
 
        }

Comparing middleware , HTTP Module and Handler

In the previous version, of ASP.NET has HTTP modules and Handler in the application life cycle, but it does not exist in the ASP.NET core application. HTTP Handlers are responsible for generating a response to the request and HTTP Modules provides application level services and features. Middleware can provide these functionalities in the ASP.NET core Application.

The following two tabs change content below.

Tom Mohan

Tom Mohan is a technologist who loves to code and build. He enjoys working on Microsoft Technologies. Tom specializes in ASP.NET MVC, Web API , Azure, C# ,WPF, SQL etc and holds a Bachelor engineering degree in Computer Science. Certification : MCSD , MCTS