ASP.NET WebForm or MVC applications rely on global.asax
to process HTTP request pipelines. Within global.asax
, each HTTP request goes through declared HTTP modules and HTTP handlers based on events. On the other hands, ASP.NET Core applications use OWIN middlewares. Actually, those middlewares now take care of what HTTP modules and HTTP handlers do. In this post, we are going to implement an HTTP request handler on a ASP.NET Core application.
Why Does It Matter?
Single Page Applications (SPA) is now a trend of web application development. SPA only contains UI logics and all other business logics are processed by calling APIs. Calling APIs through AJAX is not a problem. For example, if we use jQuery, typical AJAX call will look like:
If we need an API key for the call, the AJAX call might look like:
We might be feeling agitated here because auth key and API key are exposed within the JavaScript block, which is not we want. In this case, we usually implement API proxy (or API facade or whatever we call) so that we hide that sensitive information from the UI side. Instead, the proxy takes care of those details. Well, how can we implement the proxy then? We can implement this proxy through MVC controllers or middlewares. The good thing with middlewares to handle this is that WE DON’T NEED CONTROLLERS AT ALL. Let’s have a look.
Middleware
The main differences between HTTP modules and HTTP handler are:
- HTTP modules process requests and pass them to another modules.
- HTTP handlers process requests and return their responses to browsers.
As middlewares in ASP.NET Core take care of both HTTP modules and HTTP handlers, implementation becomes a lot easier and simpler. Here’s a basic middleware looking like:
And, in order to easily use this middleware at Startup.cs
, we can just create an extension method like:
And this extension method is placed into the Configure
method of Startup.cs
like:
Within the OWIN pipeline, middlewares are invoked by an order where they are declared. Therefore, MyMiddleware
is invoked after the previous middleware then passes HttpContext
instance to the next middleware for further processing. Here’s the clue. If we want to implement the middleware as an HTTP handler, we simply don’t run the this._next.Invoke(context)
method so that all HTTP requests complete processing at this point. Let’s make a working example.
All codes used in this post here can be found at: https://github.com/devkimchi/ASP.NET-Core-HTTP-Request-Handler-Sample
HTTP Request Header Handler Middleware
We don’t need MVC controller for our ASP.NET Core application any more because the middleware takes all AJAX requests, put some additional header and pass the requests to API server. Therefore, we can simply remove MVC middleware from the Startup.cs
and add HttpRequestHeaderHandlerMiddleware
into it.
Then, implement HttpRequestHeaderHandlerMiddleware
like:
As we can see above, it processes the request and sends HttpContext
back with response. This perfectly works as API proxy, without needing controllers. Let’s go further.
Middleware with Options Pattern
The potential problem of HttpRequestHeaderHandlerMiddleware
written above is that all custom headers are hard-coded. If we add/update/delete header values, we have to update the code. Fortunately, ASP.NET Core provides Options Pattern. This is basically for dependency injection for configuration values that are declared within appsettings.json
or environment variables. We can use this pattern for our middleware implementation with additional extension methods.
We have HttpRequestHeaderHandlerMiddlewareOptons
and this will be injected to HttpRequestHeaderHandlerMiddleware
by calling Options.Create(options)
method, which creates IOptions
instance. Here’s another extension method to declare options with lambda expressions.
Once it’s done, the HttpRequestHeaderHandlerMiddleware
needs to be updated to accept the options instance as a parameter.
Now we can use options within our middleware. Those options can be defined within appsettings.json
file, populated as a strongly-typed instance and injected to the middleware like:
So far, we have implemented a middleware as an API proxy to capture all HTTP requests, put extra header information into it and process it. With this approach, our SPA backed by ASP.NET Core would be much simpler and light-weighted.
Thanks for this post, helps me to add a simple middleware that adds 3 Http-Headers, works perfectly!
@mario That’s good to hear!