Ingredients for well-designed OWIN middleware components - Part 2

Edit this page | 1 minute read

In my last post, I talked about naming conventions and reducing the number of public dependencies, the first two ingredients of a recipe for well-designed OWIN middleware components. In this post, I'm going to talk about separating the OWIN pipeline construction from the middleware definition.

Ingredient 3: Keeping your pipeline construction clean
The first version of the UsePiercer extension method, before I added the settings argument, looked something like this:

public static IAppBuilder UsePiercer(this IAppBuilder appBuilder)
{
  HttpConfiguration configuration = BuildHttpConfiguration();

  appBuilder.Map("/api", a => a.UseWebApi(configuration));

  return appBuilder;
}

IAppBuilderis defined by the Owinpackage, but that Map method is an extension method defined in Microsoft.Owin, part of Microsoft's Katana project. Since IAppBuilder is on that public method, you can't internalize it. Your package will need to retain a dependency on the Owin package. Microsoft.Owin however, is only used within that method. Merging it in your assembly sounds like a smart thing to do.

However, without discussing the intricacies of AppFuncs and MidFuncs, it suffices to know that when the OWIN host is finalizing the construction of the OWIN pipeline (by calling the Build method of AppBuilder), some magic conversion happens between a hidden AppBuilder (which is Microsoft's implementation of IAppBuilder) to an Owin MidFunc. If you merge Microsoft.Owininto your assembly, your host won't be able to find the conversion and some weird InvalidCastException will happen. You can solve that by separating the act of adding middleware to the IAppBuilder from the construction of the middleware itself. In Piercer I used this construction:

public static IAppBuilder UsePiercer(this IAppBuilder appBuilder)
{
  appBuilder.Use(Middleware.Create(settings));
  return appBuilder;
}

Where the Middleware class returns a MidFunc:

public static Func Create()
{
  return next =>
  {
    var appBuilder = new AppBuilder();
    
    HttpConfiguration configuration =
      BuildHttpConfiguration(settings);

    appBuilder.Map(settings.Route, a => a.UseWebApi(configuration));
    appBuilder.Run(ctx => next(ctx.Environment));

    return appBuilder.Build();
  };
}

I understand that it might be a bit difficult to read (although the functional guys love this stuff ). The point is that you force this magic conversion from a nested AppBuilder to the MidFunc even before you add the middleware to the pipeline. If you take this approach, you can safely merge Microsoft.Owin into your main assembly. 

Leave a Comment