In the sixth post of this series I talked about how you can use Swagger to create real useful documentation for your API. In this seventh and probably last post, I'd like to present some spices to make that OWIN middleware component extra special.
Spice 1: Automate your entire build process using PSake
So you've completed the first version of your component and you're ready to ship it as a NuGet package. Manually creating that .nuspec file, running nuget.exe and publishing it to nuget.org is not that difficult to do. But now what? Are you going to do it like that forever? Of course not. That's why we have the power of PowerShell to our disposal, something that I already demonstrated with ingredient 6.
Spice 2: Choose the right release strategy
Now that you have your first release out of the door, you'll have to start thinking about when and how you're going to release feature versions of your component. Is any change you make that good that you can ship right away? Or do you first want to stabilize upcoming releases by shipping alpha or beta packages to be tested by your consumers. Within the git open-source world, two strategies have become kind of ad-hoc standards. There's a lot of documentation available, but the gist of it is that you should GitHubFlow if every change you do is production ready and GitFlow if you work on multiple features in parallel and get released after a period of testing. In both scenarios, GitVersion will help you automatically generate version numbers, just like I do in Piercer.
Spice 3: Decoupling through delegates
In ingredient 6 I talked about the example of having your component support an extension point in the form of the IPlugin interface. I suggested to put that interface in a separate NuGet package so that your extension point doesn't need to take a dependency on the middleware component package. An alternative approach for using an interface is to define the contract in the form of a delegate. So instead of taking the (simplified) interface definition…
public interface IPlugin
bool IsMatch(Assembly assembly);
…you can have the middleware component also take a delegate like this:
public delegate bool AssemblyMatcher(Assembly assemby);
By doing so, any method that matches that signature can be passed in place of the delegate, thereby removing the need for the plugin to implement an interface or taking a dependency at all. Delegates exist since .NET 1.0, but somehow they didn't get the love they deserved.
Spice 4: Logging like a master
Now suppose your middleware component needs some kind of logging feature to help diagnosing production issues. You could take a dependency on Log4Net, Serilog or any other popular logging library. But then you have to think of a way to expose its configuration to consumers. But what if the host is hosting multiple components, all using different logging libraries? How would it manage to get all that logging to the same log file?
This is where LibLog by Damian Hickey comes into play. It's a sophisticated little NuGet package that just adds a single source file (so no public dependencies!) and auto-detects the logging library loaded in the AppDomain at run-time. It supports NLog, Log4Net, Enterprise Library, Serilog and Loupe. So from inside your component, you just use the logging API provided by LibLog. As long as the host uses one of the supported libraries, your logging statements will automatically forwarded. Personally, I prefer the structured logging magic provided by Serilog.
Spice 5: Dependency injection without dependencies
Just like you don't want to have an extra dependency for that logging library, you don’t want to expose your prefered dependency injection container to leak into your public API. Fortunately, my favorite DI container Autofac does not rely on any static state and can be used within your container perfectly fine. However, we've observed lots of problems internalizing Autofac within your main assembly with both ILRepack as well as ILMerge. So if you can live with a thinner feature set, I can highly recommend TinyIoc. Just like LibLog, its NuGet package will just add a single source file to your solution, which means no dependencies, nada, niente.
Well, that's all folks. After seven posts I think I've completed my recipe for building professional middleware components. What do you think? Does this all make sense? Comment below or tweet me at @ddoomen.