We use cookies to provide you with a great user experience, analyze traffic and serve targeted promotions.   Learn More   Accept
Card image cap

Exploring ASP.NET Core Fundamentals - Understanding Middlewares

ASP.NET Core  • Posted one year ago

The concept of Middleware based design was introduced in the last version of dotnet framework, while it's been fully integrated in dotnet core. A middleware can be termed as a handler module that runs before a request reaching a controller. A middleware can read an input request and can modify the request or decide if it can go further or needs to be responded back within itself. A typical example of a middleware architecture can be the Authorization filter used for authenticating and authorizing incoming requests for a controller. An Authorization middleware sits before a controller and validates the Authorization header value passed before letting it pass through it. Another usecase for a Middleware can be a Logger which asynchronously logs all the input requests and responses that are bound to the application.

A middleware is defined in the Startup class as below:

public class Startup {

	public void ConfigureServices(IServiceCollection services) {

		// services definition

		services.AddSingleton<MyInjectableDependency>();

		services.AddTransient<MyLocalInjectableDependency>();

	}

	public void Configure(IApplicationBuilder app) {

		app.UseMiddleware<MyMiddlewareClass>();

	}

}

which registers the class MyMiddlewareClass as a Middleware and adds it to the request pipeline. And so all the requests bound to the application first pass through the class MyMiddlewareClass before reaching a controller. The class can contain any logic for handling requests or responses.

public class MyMiddlewareClass {

	private RequestDelegate _next;

	public MyMiddlewareClass(RequestDelegate next) {

		_next = next;

	}

	public async Task InvokeAsync() {

		Console.WriteLine("MyMiddlewareClass is now Invoked");

		_next.Invoke();

	}
}

In the above code snippet, which defines a sample structure of a Middleware implementation, contains a constructor which takes one or more parameters. The RequestDelegate variable "next" can be used to explicitly pass on the control to the next middleware in the pipeline on any required condition. When the middleware is invoked the InvokeAsync (or Invoke for synchronous calls) method is called and the incoming request object is available under the HttpContext property of the class (which can be injected via the Invoke method).

Injecting Dependencies into a Middleware:

Now that a middleware contains logic for handling requests, we might require injecting dependencies into it (say for example a database context, or a Logger singleton). For that we can have two options: The constructor or the Invoke method. The usage depends on the scope of the dependency within the class. If the dependency is a scoped life-time service, it needs to be injected via the Invoke method, since the middleware is built only once when the startup class is invoked (at the time of app bootstrap) and not created for every request.

Example:

public class MyMiddlewareClass {

	private RequestDelegate _next;
	private MyInjectableDependency _mIdp;

	// Any dependencies which might span across 
  // the class scope can be injected through the constructor
	public MyMiddlewareClass(RequestDelegate next, MyInjectableDependency mIdp) {

		_next = next;
		_mIdp = mIdp;

	}

	// Any dependencies which are scoped just under 
  // Invoke method are injected into Invoke directly
	public async Task InvokeAsync(MyScopedInjectableDependency mLiDp, 
                                              HttpContext context) {

		Console.WriteLine("MyMiddlewareClass is now Invoked");

		mLiDp.SomeMethodToInvoke("This is MyMiddlewareClass");

		this.LogicalMethod();

		if(context.User.Identity.IsAuthenticated) {
			//explicitly call the next Middleware in the pipeline.
			_next.Invoke();
		}
		else {
			//return back the response to the user.
			context.Response.WriteAsync("Invalid User. 401");
			return;
		}
	}

	private void LogicalMethod() {

		_mIdp.SomeMethodToInvoke("This is LogicalMethod of the middleware");

	}
}