Your browser may have trouble rendering this page. See supported browsers for more information.

This page shows the source for this entry, with WebCore formatting language tags and attributes highlighted.

Title

Encodo's configuration library for Quino: part II

Description

In this article, we'll continue the discussion about configuration started in <a href="{app}view_article.php?id=3132">part I</a>. We wrapped up that part with the following principles to keep in mind while designing the new system. <ul> Consistency Opt-in configuration Inversion of Control Configuration vs. Execution Common Usage </ul> <h>Borrowing from ASP.NET vNext</h> Quino's configuration inconsistencies and issues have been well-known for several versions---and years---but the opportunity to rewrite it comes only now with a major-version break. Luckily for us, ASP.NET has been going through a similar struggle and evolution. We were able to model some of our terminology on the patterns from their next version. For example, ASP.NET has moved to a pattern where an application-builder object is passed to user code for configuration. The pattern there is to include <i>middleware</i> (what we call "configuration") by calling extension methods starting with "Use". Quino has had a similar pattern for a while, but the method names varied: "Integrate", "Add", "Include"; these methods have now all been standardized to "Use" to match the prevailing .NET winds. <h>Begone configuration and feedback</h> Additionally, Quino used to make a distinction between an application instance and its "configuration"---the template on which an application is based. No more. Too complicated. This design decision, coupled with the promotion of a platform-specific "Feedback" object to first-level citizen, led to an explosion of generic type parameters.<fn> The distinction between configuration (template) and application (instance) has been removed. Instead, there is just an application object to configure. The feedback object is now to be found in the service locator. An application registers a platform-specific feedback to use as it would any other customization. <ft>The <c>CustomWinformFeedback</c> in the Quino 1.x code at the end of this article provides a glaring example.</ft> <h>Hello service locator</h> ASP.NET vNext has made the service locator a first-class citizen. In ASP.NET, applications <i>receive</i> an <c>IApplicationBuilder</c> in one magic "Configure" method and <i>receive</i> an <c>IServiceCollection</c> in another magic "ConfigureServices" method. In Quino 2.x, the application is in charge of creating the service container, though Quino provides a method to create and configure a standard one (SimpleInjector). That service locator is passed to the <c>IApplication</c> object and subsequently accessible there. Services can of course be registered directly or by calling pre-packaged Middleware methods. Unlike ASP.NET vNext, Quino 2.x makes no distinction between configuring middleware and including the services required by that middleware. <h>Begone configuration hierarchy</h> Quino's configuration library has its roots in a time before we were using an IOC container. The configuration was defined as a hierarchy of configuration classes that modeled the following layers. <ul> A base implementation that makes only the most primitive assumptions about an application. For example, that it has a <c>RunMode</c> ("debug" or "release") or an exit code or that it has a logging mechanism (e.g. <c>IRecorder</c>). The "Core" layer comprises application components that are very common, but do not depend on Quino's metadata. And, finally, the "Meta" layer includes configuration for application components that extend the core with metadata-dependent versions as well as specific components required by Quino applications. </ul> While these layers are still somewhat evident, the move to middleware packages has blurred the distinction between them. Instead of choosing a concrete configuration base class, an application now calls a handful of "Use" methods to indicate what kind of application to build. There are, of course, still helpful top-level methods---e.g. <c>UseCore()</c> and <c>UseMeta()</c> methods---that pull in all of the middleware for the standard application types. But, crucially, the application is free to tweak this configuration with more granular calls to register custom configuration in the service locator. This is a flexible and transparent improvement over passing esoteric parameters to monolithic configuration methods, as in the previous version. <h>An example: Configure a software updater</h> Just as a simple example, whereas a Quino 1.x standalone application would set <c>ICoreConfiguration.UseSoftwareUpdater</c> to <c>true</c>, a Quino 2.x application calls <c>UseSoftwareUpdater()</c>. Where a Quino 1.x Winform application would inherit from the <c>WinformFeedback</c> in order to return a customized <c>ISoftwareUpdateFeedback</c>, a Quino 2.x application calls <c>UseSoftwareUpdateFeedback()</c>. The software-update feedback class is defined below and is used by both versions. <code> public class CustomSoftwareUpdateFeedback : WinformSoftwareUpdateFeedback<imetaapplication> { protected override ResponseType DoConfirmUpdate(TApplication application, ...) { ... } } </code> That's where the similarities end, though. The code samples below show the stark difference between the old and new configuration systems. <h level="3">Quino 1.x</h> As explained above, Quino 1.x did not allow registration of a sub-feedback like the software-updater. Instead, the application had to inherit from the main feedback and override a method to create the desired sub-feedback. <code> class CustomWinformFeedback : WinformFeedback { public virtual ISoftwareUpdateFeedback<tapplication> GetSoftwareUpdateFeedback<tapplication,>() where TApplication : ICoreApplication<tconfiguration,> where TConfiguration : ICoreConfiguration where TFeedback : ICoreFeedback { return new CustomSoftwareUpdateFeedback(this); } } var configuration = new CustomConfiguration() { UseSoftwareUpdater = true } WinformDxMetaConfigurationTools.Run( configuration, app => new CustomMainForm(app), new CustomWinformFeedback() ); </code> The method-override in the feedback was hideous and scared off a good many developers. not only that, the pattern was to use a magical, platform-specific <c>WinformDxMetaConfigurationTools.Run</c> method to create an application, run it and dispose it. <h level="3">Quino 2.x</h> Software-update feedback-registration in Quino 2.x adheres to the principles outlined at the top of the article: it is <b>consistent</b> and uses <b>common patterns</b> (functionality is included and customized with methods named "Use"), configuration is <b>opt-in</b>, and the <b>IOC</b> container is used throughout (albeit implicitly with these higher-level configuration methods). <code> using (var application = new CustomApplication()) { application.UseMetaWinformDx(); application.UseSoftwareUpdater(); application.UseSoftwareUpdaterFeedback(new CustomSoftwareUpdateFeedback()); application.Run(app => new CustomMainForm(app)); } </code> Additionally, the program has complete control over creation, running and disposal of the application. No more magic and implicit after-the-fact configuration. <h>What comes after configuration?</h> In the next and (hopefully) final article, we'll take a look at configuring execution---the actions to execute during startup and shutdown. Registering objects in a service locator is all well and good, but calls into the service locator have to be made in order for anything to actually <i>happen</i>. Keeping this system flexible and addressing standard application requirements is a challenging but not insurmountable problem. Stay tuned.