OWIN v1.0 is now over a year old, and Microsoft is shipping its Katana implementation as part of its Visual Studio 2013 ASP.NET project templates. I think this a tremendous victory for both Microsoft and its community around open source efforts. Congratulations to all involved!
As with all such victories, however, there are a few items that could have gone a bit better. The one I’d like to focus on in this post is
IAppBuilder is a simple interface meant to provide a common builder API similar to that found in Rack and Connect. Unfortunately, the
IAppBuilder does not expose any members that relate to the OWIN application delegate signature. Worse,
IAppBuilder is the only type contained in the owin.dll you can pull from NuGet, and several packages now reference and even require this dependency.
Why does this matter?
First, the big debate from the outset was to ensure no dependency was necessary. The original owin.dll had only the standard type aliases for the
AppFunc and other delegate signatures of the pre-1.0 OWIN spec. Once we moved to the simpler
Func<IDictionary<string, object>, Task> signature, the need for a common assembly disappeared, only it was replaced with the
IAppBuilder. I don’t recall exactly when or why this happened. The major problem is that implementations like Simple.Owin, Fix, and Dyfrig, which don’t rely on
IAppBuilder, are incompatible with a majority of the current “OWIN” middlewares available today. Here’s an example. You can read more of the discussion here.
Second, the lack of prescribed types in
IAppBuilder members means that different implementations may not adhere to the Liskov Substitution Principal. In fact, this is currently the case in the Fix library referenced above. Further, unless you are willing to read the source for the
IAppBuilder implementation you are using, you may have trouble writing a middleware adapter that works. (Note: It’s not hard to write a middleware using
IAppBuilder, but the interface is insufficient to understand what is required.)
Third, the initial
IAppBuilder defined in Katana presents an interesting but also undefined behavior of “falling through” to the next middleware when a 404 is returned. This is a fantastic invention that really helps achieve a terrific goal of hosting different application frameworks side-by-side in the same process. However, this isn’t part of the OWIN specification and not necessary for all applications. In addition, the choice of a 404 as a meaningful event seems a bit of a hack. In my opinion, a proper router middleware would better solve this problem.
IAppBuilder blocked the (perceived or real) problem of not having defined a middleware signature for OWIN applications. For my F#-based OWIN applications, this wasn’t a problem, since F# supports easy function composition that works really well with the OWIN signature. However, many developers trying to use OWIN in C# expressed this as a problem, and a few options have appeared, most of which more or less mimic the function composition I use in F#. The current consensus appears to be that
Func<AppFunc, AppFunc> is the right approach. However, that decision is awaiting a reboot of the OWIN governance model to sort out.
I want to make it clear that I think Katana is a terrific product. I’m thrilled that it has made it into the ASP.NET templates and will become the standard for writing ASP.NET applications in the not so distant future. I’m even more thrilled at how Microsoft picked up and adopted the effort and worked with the community. In fact, two Microsoft employees were responsible for writing the OWIN specification.
Nevertheless, I want to make sure Katana does not become OWIN. OWIN is meant to be an open specification with no default implementation.
IAppBuilder is not specific to Katana, but Katana does possess the best example and most popular implementation. Others are free to incorporate
IAppBuilder but should pay close attention to the Katana implementation to do it right.
Most importantly, know that you don’t need
IAppBuilder at all to build an OWIN application or host. OWIN relates directly to the
AppFunc signature and environment dictionary as defined in the specification. Build to your heart’s content.