Over a million developers have joined DZone.

Ingredients for Well-Designed OWIN Middleware Components (Part 1)

DZone's Guide to

Ingredients for Well-Designed OWIN Middleware Components (Part 1)

Learn more about some of the practices that emerge from building components that offer HTTP-based services.

· Integration Zone
Free Resource

Modernize your application architectures with microservices and APIs with best practices from this free virtual summit series. Brought to you in partnership with CA Technologies.

My main focus the last couple of months has been on building components that offer HTTP-based services. This whole component-oriented focus is something we've been focusing on the last year or so because we wanted to actively trying move away from building monolithic systems. Tools like OWIN, NuGet and ILMerge have enabled new ways of building .NET software at scale that we're trying to benefit from. This series of posts intends to list some of the practices that emerged from building those components.

To prevent ending up with a theoretical discussion, I've build an accompanying example project called Piercer. Piercer is a little OWIN middleware component that you can host in your OWIN-aware console application, Windows Service or IIS-based web site. It exposes an end-point at route api/piercer/assemblies that lists the run-time assemblies in the AppDomain as well as their version and culture. For the sake of this post, its functionality is mostly irrelevant. It’s the mechanism of how it has been build that is important for this discussion.

Ingredient 1: Setup your middleware using the UseXXX convention

It's not an official requirement, but almost all middleware components are added to an OWIN pipeline builder using a extension method on IAppBuilder that starts with Use. And if you want to allow developers to configure your component, let them pass in a settings class as well.

var appBuilder = new AppBuilder();
appBuilder.UsePiercer(new PiercerSettings().Ignoring("Piercer.Middleware"));

Following those conventions makes your component more approachable. I myself prefer a fluent API for the settings, but whether you want to adopt that is up to you.

Ingredient 2: Minimize public dependencies
The most painful experience you can give to the consumers of your middleware component is the one where adding the NuGet package involves including several other NuGet packages as well. It gets worse if that consumer is already depending on other packages that on turn depend on different versions of those same packages. Avoiding this so-called diamond dependency problem is crucial to a successful component.

One of the most effective ways of solving that problem is to internalize the assemblies your component depends on and which are not exposed through your public API. Both ILMerge, which has been discontinued by Microsoft, and ILRepack, the open-source replacement for the first, can do the job. You'll have to experiment with which one works best unfortunately. Neither of them are the silver bullet to merging assemblies. I've been successful in using the ILRepack in one project, but it failed in the other. It requires a little bit of trial-and-error to get it right. But if you do, you'll make consuming your component almost painless. In the Piercer project, I've used the following PowerShell snippet to get all its dependencies merged into a single assembly like this:

Merge-Assemblies `
	-outputFile "$NugetOutputDir\Piercer.Middleware.dll"`
	-libPaths @(
	-files @(

The Merge-Assemblies function is a little wrapper that invokes ILRepack with the right arguments. You can find its definition here.

The Integration Zone is proudly sponsored by CA Technologies. Learn from expert microservices and API presentations at the Modernizing Application Architectures Virtual Summit Series.

integration ,middleware ,.net ,owin

Published at DZone with permission of Dennis Doomen, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}