Blogger news

Blogger templates

Thursday, April 23, 2020

ASP.Net Core Custom Middleware

ASP.Net core middleware is a component or piece of code executes in the request/response pipeline which decides whether to pass the request to the next component in the pipeline or not. Middleware does some kind of work before deciding to pass the request to the next component in the pipeline.
Let me explain with an example, say I want to log all the incoming requests first before it hits to any other component in the application. Also, I want to read a custom header value from the request and make it available throughout the application. Here we can create two custom middleware, the first one will write the log and the second one will read the value from the header and inject it to all needed components. This is what we are going to build today.
Before start building let me show a diagram which shows the execution of ASP.Net core middleware,
ASP.Net core middleware
As you can see in the diagram above request pipeline consists of a sequence of middleware’s, called one after the other. Each middleware can perform operations before and after it delegates the request/response to the next middleware.
ASP.NET Core has many built-in middlewares (Example:- Authentication, MVC, Routing, etc.). But in this article, we are focusing on how to build middleware on our own and plug it with ASP.Net core request/response pipeline.
Let us start building custom middleware for below two scenarios,
  • Logging Middleware
  • Middleware to read request header

Rules to build custom middleware

There are certain rules to follow for writing a middleware. Middleware is generally encapsulated in a class and exposed with an extension method. The middleware class must include:
  • A public constructor with a parameter of type RequestDelegate.
  • A public method named Invoke or InvokeAsync. This method must return a Task and accept the first parameter of type HttpContext. Additional parameters for the Invoke/InvokeAsync are populated by dependency injection (DI).
No worries If you didn’t understand the rules. We will see each one of these in the example we are going to build. Enough of theory, let’s build our first custom middleware

Custom Logging Middleware

Here we will build a middleware where all requests should hit first in the pipeline which logs the request body. Let’s name the class “LoggerMiddleware”, which looks like below,
Now go back to the rule which we have mentioned before to build a custom middleware. We have exactly followed those rules. We have a public constructor with a parameter of type “RequestDelegate” in the LoggerMiddleware class. Also, we have a public method named InvokeAsync which returns a Task and accepts the first parameter of type HttpContext.
To enable logging we have injected ILoggerFactory, which is a .Net core framework service. we don’t need to worry about injecting ILoggerFactory as .Net core will take care of injecting framework services (Example of framework services IApplicationBuilder, IHostingEnvironment, ILoggerFactory, etc).
The next step is to create an extension method to expose the middleware. Middleware extension method exposes the middleware through IApplicationBuilder,
Here we have extended IApplicationBuilder to use the new middleware we have build, LoggerMiddleware. Now we are all set with the middleware and the only thing left is to use it.
To use any .Net core middleware we have to invoke it in the Configure method of Startup.cs.
By adding the line app.UseLogger() our application is ready to use the middleware we build. We have added it as the first component in the pipeline to make sure it will always log whenever a request hits the application.

Custom Client Configuration Middleware

Let’s build our second custom middleware. As an example scenario assumes in every API request client will pass client name in the header and we need to use that client name in multiple parts of the application along with the date and time client invoked the API. We are going to build a middleware for this example scenario where we read the header from the client and make it available in other places of the application. First, we will create an interface named “IClientConfiguration” with properties ClientName and InvokedDateTime. In the middleware, we set both properties. Now where ever we injected IConfiguration will have those values we set in the middleware.
Before start building this middleware I need to discuss a bit about middleware lifetime. Middleware is constructed once per application lifetime. Because middleware is constructed at app startup, not per-request, scoped lifetime services used by middleware constructors aren’t shared with other dependency-injected types during each request. If you must share a scoped service between your middleware and other types, add these services to the Invoke method’s signature. The Invoke method can accept additional parameters. Because of this lifetime rule, we will inject “IClientConfiguration” as a parameter to InvokeAsync method. If you couldn’t follow what I just said no worries you will get it after we built it. So let’s build it straightway. First things first, let’s add the interface “IClientConfiguration”,
Next, a class which Implements IClientConfiguration,
And I have resolved the dependency of IClientConfiguration in the ConfigureServices method of Startup.cs,
Now let’s follow the rules we defined before to create custom middleware,
We have injected IClientConfiguration to the InvokeAsync method and we have set the ClientName property of IClientConfiguration by reading the header “CLIENTNAME”, which each client will pass during the API call.
Let’s create the extension method to expose the middleware,
Now we are ready to use this middleware so just add the below snippet in the Configure method,
Now where ever we have IClientConfiguration injected there we will get the “CLIENTNAME” header value and the InvokedDateTime. Let’s test it.
For testing purpose I am creating a sample controller named ConfigurationController with a GET method which returns ClientConfiguration as such to see are we getting back the header we passed along with the DateTime we invoked,
When I invoke the API with the header “CLIENTNAME” I am expecting back the header values we passed and the DateTime invoked. Here it is,
You can clone the complete source code from my git repo,

No comments:

Post a Comment