Realworld example ASP.NET Core 1.0’s Middleware

Synopsis: HTTP Modules and HTTP Handlers are not used anymore with ASP.NET Core 1.0. But what if your web app relies on HTTP Modules/Handlers to function? Well, I had a web application that relied on HTTP Modules and a Handler. In this article I will show you how this problem is solved with ASP.NET Core 1.0’s Middleware!

Intro

Middleware are software components that can be integrated into the HTTP pipeline and intercept HTTP requests and responses[1]. To support OWIN, thus decoupling the web application from the web server, ASP.NET Core provides a standard way to implement Middleware as defined by OWIN [2]. Conceptually the way Middleware works looks like:

concept-middleware
Figure 1: Concept Middleware

So if you want to intercept the HTTP pipeline you’ll have to use Middleware because HTTP Modules and Handlers are gone in ASP.NET Core 1.0… Or are they?

AspNetCoreModule as a HTTP Module

If you create a new ASP.NET Core solution you will still find a “web.config” file in the project’s root. The content is as follows:

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <!--
    Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
  -->

  <system.webServer>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
    </handlers>
    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
  </system.webServer>
</configuration>

This file’s only purpose is to allow the web application to run on IIS. This is done by adding the ASP NET Core Module (an new native IIS module) [3] as a handler. This module makes it possible for external processes that listen to HTTP requests, like “dotnet.exe”, to proxy requests into it and have process management from IIS.

Side note:ASP NET Core Module replaces the HttpPlatformHandler introduced with RC1. Just for emphasis of how important the HttpPlatformHandler is, Scott Hanselmann explained a lot more about this generic reverse proxy mechanism [4], which provides endless possibilities. But the team moved forward with a module which has Asp.Net specific features, as opposed to a generic reverse proxy.

IISPlatformHandler as Middleware

To start explaining middleware I’d like to go back to RC1’s IISPlatformHandler. You see, you used to integrate the IIS HttpPlatformHandler middleware to be able to interact with the module. You did this by adding the following line of code to the Configure method of the Startup class:

app.UseIISPlatformHandler();

Side note: Now you add the “UseIISIntegration” extension method to the WebHostBuilder in the static void Main of the Program class.

UseIISPlatformHandler() is actually an Extension Method extending IApplicationBuilder and what it does as copied from the summary is:

“Adds middleware for interacting with the IIS HttpPlatformHandler reverse proxy module. This will handle forwarded Windows Authentication, request scheme, remote IPs, etc..”

And when we look at the sourcecode on GitHub[5] to see what this extension method exactly does for us, we see the following code (at the overload with no options):

if (app == null)
{
    throw new ArgumentNullException(nameof(app));
}

return app.UseMiddleware<IISPlatformHandlerMiddleware>(new IISPlatformHandlerOptions());

As mentioned before UseIISPlatformHandler is just an extension method to hide the complexities of setting up and initializing the IISPlatformHandlerMiddleware middleware. You can set up and add any middleware class to the HTTP pipeline via the UseMiddleware method you see above. All your middleware class needs is a constructor to request via constructor injection the RequestDelegate, as IISPlatformHandlerMiddleware[6] demonstrates:

public IISPlatformHandlerMiddleware(RequestDelegate next, IISPlatformHandlerOptions options)
{
    if (next == null)
    {
        throw new ArgumentNullException(nameof(next));
    }
    if (options == null)
    {
        throw new ArgumentNullException(nameof(options));
    }
    _next = next;
    _options = options;
}

And an Invoke method:

public async Task Invoke(HttpContext httpContext)
{
    UpdateScheme(httpContext);

    UpdateRemoteIp(httpContext);

    var winPrincipal = UpdateUser(httpContext);

    var handler = new AuthenticationHandler(httpContext, _options, winPrincipal);
    AttachAuthenticationHandler(handler);

    try
    {
        await _next(httpContext);
    }
    finally
    {
        DetachAuthenticationhandler(handler);
    }
}

Side note: I will not go into details about what the IISPlatformHandlerMiddleware exactly does, because this is an article about writing your own Middleware.

You could even skip requesting the RequestDelegate in your constructor if you always want your middleware to be the last one in the HTTP pipeline. But all in all, implementing your own Middleware seems easy enough. Let’s review the case quickly for this article and then move on to building the middleware:

Case

This is a case about healthcare in The Netherlands. If anything is unclear please let me know. General practitioners from private practices should be able to log on to a website on which they can leave notes about patients of which they suspect they’ll need to visit a medical centre at night or in the weekend. Every medical centre could potentially be owning a different database on a different server. When the GP logs in, we want to retrieve all the databases and their servers the GP is allowed on, in order to retrieve the patient this GP is allowed to see. We used to do this in a HTTP module and now we want to do this with Middleware.

Writing Middleware

For this example we are going to assume the user is authenticated and we only need to authorize the user, by providing a collection of databases and their servers. So to tackle this problem at a bare minimum I came up with the following middleware as an example:

public class GeneralPractitionerAuthorizationMiddleware
{
	private RequestDelegate Next { get; }
	private IGeneralPractitionerAuthorizationRepository Repository { get; }
	private CurrentGeneralPractitionerService Service { get; }
	private CurrentGeneralPractitionerAuthorizationsService AuthorizationService { get; }

	public GeneralPractitionerAuthorizationMiddleware(RequestDelegate next, 
		IGeneralPractitionerAuthorizationRepository repository,
		CurrentGeneralPractitionerService service,
		CurrentGeneralPractitionerAuthorizationsService authorizationService)
	{
		if (next == null) throw new ArgumentNullException(nameof(next));
		if (repository == null) throw new ArgumentNullException(nameof(repository));
		if (service == null) throw new ArgumentNullException(nameof(service));
		if (authorizationService == null) throw new ArgumentNullException(nameof(authorizationService));
		Next = next;
		Repository = repository;
		Service = service;
		AuthorizationService = authorizationService;

	}

	public async Task Invoke(HttpContext context)
	{
		var generalPractitionerAuthorizations = Repository.GetAuthorizationsForGeneralPractitioner(Service.GetId());
		AuthorizationService.Authorizations = generalPractitionerAuthorizations;
		await Next.Invoke(context);
	}
}

You see the RequestDelegate as discussed before, because I want to call the next middleware in the chain.
Then a Repository, which is going to pretend to retrieve a collection of databases and their servers from some persistent storage.
Then a fake Service, which holds the Identifier of the currently logged in general practitioner.
And an AuthorizationService to simply hold the retrieved collection in memory, so this example didn’t get polluted with all kinds of non-middleware related material.

Side note: Please keep in mind that it’s just an example to explain Middleware. Authorization should be done via claims and kept with the ClaimsPrincipal via Cookie middleware or another means of persistence.

I request all these items via the constructor, because middleware uses the native ability of ASP.NET Core to utilize Dependency Injection, which I’ll discuss later.

Then you see the Invoke method which all Middleware classes need to have. The implementation of the Invoke method doesn’t matter, you can check that out at the GitHub repository if you wish[7]. The line of code that does matter however is: “await Next.Invoke(context);”, which makes sure the pipeline continues.

Side note: Important to note is that you can also have logic after the “await Next.Invoke(context);”, to process some more logic when the response returns.

I’ve followed the convention to hide the details about how to use this middleware in an extension method, like so:

public static class GeneralPractitionerAuthorizationMiddlewareExtensions
{
	public static IApplicationBuilder UseGeneralPractitionerAuthorizationMiddleware(this IApplicationBuilder builder)
	{
		return builder.UseMiddleware<GeneralPractitionerAuthorizationMiddleware>();
	}
}

It’s not that complex right now, I simply call the “UseMiddleware” method, which handles everything, from hooking it up into the pipeline, to handling the dependencies. Still need to register those dependencies though, and I’ve followed the same pattern of hiding the details in an extension method again:

public static class GeneralPractitionerAuthorizationServiceCollectionExtensions
{
	public static IServiceCollection AddGeneralPractitionerAuthorization(this IServiceCollection services)
	{
	services.AddSingleton<IGeneralPractitionerAuthorizationRepository, GeneralPractitionerAuthorizationRepository>();
        services.AddSingleton<CurrentGeneralPractitionerService>();
			services.AddSingleton<CurrentGeneralPractitionerAuthorizationsService>();
			return services;
		}
	}

Nothing fancy I reckon. Just added the types as singletons. Of course in a real world application you should be careful with the singleton, but it made this example clean and simple. You can return the instance of IServiceCollection to keep the API fluent if you wish.

Now you can add this line of code to the ConfigureServices method of the Startup class:

services.AddGeneralPractitionerAuthorization();

And this line of code to the “Configure” method:

app.UseGeneralPractitionerAuthorizationMiddleware();

Middleware without writing a class

The request pipeline is built by using Request Delegates, which you saw in action earlier. What if your case is so simple that you don’t want to write an entire class? Well then you can configure these delegates using the “Run”, “Map” and “Use” extension methods from IApplicationBuilder. Often the Request Delegates are then specified using in-line anonymous methods. A simple example of the “Use” extension method could be:

app.Use(async (context, next) =>
{
	context.Request.Headers.Add("SomeExampleKey", "SomeExampleValue");
	await next.Invoke();
});

You could for instance add a value to the HTTP headers of the request, or log information, and many more possibilities. An example of the “Run” extension method is in every project you create:

app.Run(async (context) =>
{
	await context.Response.WriteAsync("Hello World!");
});

Keep in mind that a “Run” middleware is always the last middleware in the pipeline, because it doesn’t call a Request Delegate and formulates the response first.

If you need to branch off the request pipeline you need “Map”. You can check out an example of “Map” (or to be more accurate “MapWhen”) in the referenced example on my GitHub.

Conclusion

Writing your own reusable middleware is very easy. All it needs is an Invoke method, and in most cases a Request Delegate. ASP Handlers and Modules are not platform agnostic and therefor needed to go. If you ask me, what we have now is infinitely better. Less brittle configurations in dodgy XML files. It is cross platform, you can even be compliant with OWIN if you must. Go check out my sample on GitHub if you haven’t already! Small caveat, I’ve used it a little bit as my own playground, but so can you. Thank you for reading!

Links

  1. Middleware: https://docs.asp.net/en/latest/fundamentals/middleware.html
  2. OWIN: https://docs.asp.net/en/latest/fundamentals/owin.html
  3. AspNetCoreModule: https://github.com/aspnet/Announcements/issues/164
  4. HttpPlatformHandler with Scott Hanselman: https://channel9.msdn.com/Shows/Azure-Friday/The-HTTP-Platform-Handler-with-Scott-Hanselman
  5. IISPlatformHandlerMiddlewareExtensions: https://github.com/aspnet/IISIntegration/blob/c93e4f09f2e5648c70bfa86748911f7ea0c18148/src/Microsoft.AspNet.IISPlatformHandler/IISPlatformHandlerMiddlewareExtensions.cs
  6. IISPlatformHandlerMiddleware: https://github.com/aspnet/IISIntegration/blob/c93e4f09f2e5648c70bfa86748911f7ea0c18148/src/Microsoft.AspNet.IISPlatformHandler/IISPlatformHandlerMiddleware.cs
  7. Middleware sample on GitHub: https://github.com/DannyvanderKraan/MiddleWareSample
Advertisements

About Danny

Bachelor in Commercial ICT MCTS Winforms .NET 2.0 MCTS ASP.NET 3.5 PSM I
This entry was posted in .NET programming, ASP.NET Core 1.0, ASP.NET MVC, C#, C# 6.0, Dependency Injection, DNX and tagged , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s