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

Title

Quino v2.0: Logging, Dependencies, New Assemblies & Nuget

Description

The summary below describes major new features, items of note and breaking changes. The <a href="https://secure.encodo.ch/jira/secure/ReleaseNote.jspa?projectId=10006&version=19704">full list of issues</a> is also available for those with access to the Encodo issue tracker. <h>Highlights</h> In the <a href="{app}/view_article.php?id=3128">beta1</a> and <a href="{app}/view_article.php?id=3142">beta2</a> release notes, we read about changes to configuration, dependency reduction, the data driver architecture, DDL commands, security and access control in web applications and a new code-generation format. In 2.0 final---which was actually released internally on November 13th, 2015 (a Friday)---we made the following additional improvements: <ul> <b>Moved</b> the <b>metadata</b> table maintained for the schema-migrator to a proper Quino <b>module</b>. (<a href="https://secure.encodo.ch/jira/browse/QNO-4741">QNO-4741</a>) <b>Rebuilt</b> the <b>logging</b> and messaging API and drastically simplified the implementation throughout (<a href="https://secure.encodo.ch/jira/browse/QNO-4688">QNO-4688</a> w/sub-tasks, <a href="https://secure.encodo.ch/jira/browse/QNO-4954">QNO-4954</a>) <b>Split</b> Encodo and Quino into dozens of <b>new</b>, independent and properly decoupled <b>assemblies</b> (<a href="https://secure.encodo.ch/jira/browse/QNO-4678">QNO-4678</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4672">QNO-4672</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4670">QNO-4670</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4376">QNO-4376</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4920">QNO-4920</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4926">QNO-4926</a>) Rebuilt the <b>configuration</b> and <b>application-startup</b> API (<a href="https://secure.encodo.ch/jira/browse/QNO-4855">QNO-4855</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4051">QNO-4051</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4895">QNO-4895</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4931">QNO-4931</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4930">QNO-4930</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4949">QNO-4949</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4659">QNO-4659</a> w/sub-tasks, <a href="https://secure.encodo.ch/jira/browse/QNO-4950">QNO-4950</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4857">QNO-4857</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4910">QNO-4910</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4934">QNO-4934</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4898">QNO-4898</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4935">QNO-4935</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4937">QNO-4937</a>) Changed delivery and <b>deployment</b> for Quino and all products to <b>Nuget packages</b> (<a href="https://secure.encodo.ch/jira/browse/QNO-4916">QNO-4916</a>) Added scripting and support for continuous integration and deployment of Quino packages and symbols via <b>TeamCity</b> (<a href="https://secure.encodo.ch/jira/browse/QNO-4871">QNO-4871</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4932">QNO-4932</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-3437">QNO-3437</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4433">QNO-4433</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4494">QNO-4494</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4871">QNO-4871</a>) Restructured and refactored the standard testing base-classes and <b>testing support</b> for Quino products (<a href="https://secure.encodo.ch/jira/browse/QNO-4963">QNO-4963</a>) Improved and fixed <b>code-generation</b> for both v1 and v2 formats (<a href="https://secure.encodo.ch/jira/browse/QNO-4804">QNO-4804</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4828">QNO-4828</a>, <a href="https://secure.encodo.ch/jira/browse/QNO-4897">QNO-4897</a>) Refactored the <b>application server</b> API to improve decoupling and extensibility (<a href="https://secure.encodo.ch/jira/browse/QNO-4927">QNO-4927</a>) </ul> These notes are being published for completeness and documentation. The first publicly available release of Quino 2.x will be 2.1 or higher (release notes coming soon). <h>Breaking changes</h> <img attachment="upgrade_to_quino_2_big_project.png" align="right" caption="A big project will have a lot of errors (over 12,000!)">As we've mentioned before, this release is absolutely merciless in regard to backwards compatibility. Old code is not retained as <c>Obsolete</c>. Instead, a project upgrading to 2.0 will encounter compile errors. The following notes serve as an incomplete guide that will help you upgrade a Quino-based product. As I wrote in the release notes for <a href="{app}/view_article.php?id=3128">beta1</a> and <a href="{app}/view_article.php?id=3142">beta2</a>, if you arm yourself with a bit of time, ReSharper and the release notes (and possibly keep an Encodo employee on speed-dial), the upgrade is not difficult. It consists mainly of letting ReSharper update namespace references for you. <h level="3">Global Search/Replace</h> Instead of going through the errors (example shown to the right) one by one, you can take care of a lot of errors with the following search/replace pairs. <ul> <c>Encodo.Quino.Data.Persistence</c> => <c>Encodo.Quino.Data</c> <c>IMetaApplication</c> => <c>IApplication</c> <c>ICoreApplication</c> => <c>IApplication</c> <c>GetServiceLocator()</c> => <c>GetServices()</c> <c>MetaMethodTools.GetInstance</c> => <c>DataMetaMethodExtensions.GetInstance</c> <c>application.ServiceLocator.GetInstance</c> => <c>application.GetInstance</c> <c>Application.ServiceLocator.GetInstance</c> => <c>Application.GetInstance</c> <c>application.ServiceLocator</c> => <c>application.GetServices()</c> <c>Application.ServiceLocator</c> => <c>Application.GetServices()</c> <c>application.Recorder</c> => <c>application.GetLogger()</c> <c>Application.Recorder</c> => <c>Application.GetLogger()</c> <c>session.GetRecorder()</c> => <c>session.GetLogger()</c> <c>Session.GetRecorder()</c> => <c>Session.GetLogger()</c> <c>Session.Application.Recorder</c> => <c>Session.GetLogger()</c> <c>FileTools.Canonicalize()</c> => <c>PathTools.Normalize()</c> <c>application.Messages</c> => <c>application.GetMessageList()</c> <c>Application.Messages</c> => <c>Application.GetMessageList()</c> <c>ServiceLocator.GetInstance</c> => <c>Application.GetInstance</c> <c>MetaLayoutTools</c> => <c>LayoutConstants</c> <c>GlobalContext.Instance.Application.Configuration.Model</c> => <c>GlobalContext.Instance.Application.GetModel()</c> <c>IMessageRecorder</c> => <c>ILogger</c> <c>GetUseReleaseSettings()</c> => <c>IsInReleaseMode()</c> <c>ReportToolsDX</c> => <c>ReportDxExtensions</c> </ul> Although you can't just search/replace everything, it gets you a long way. <h level="3">Model-Building Fixes</h> These replacement pairs, while not recommended for global search/replace, are a handy guide for how the API has generally changed. <ul> <c>*Generator<c> => *</c>Builder</c> <c>SetUpForModule<c> => </c>CreateModule</c> <c>Builder.SetElementVisibility(prop, true)<c> => </c>prop.Show()</c> <c>Builder.SetElementVisibility(prop, false)<c> => </c>prop.Hide()</c> <c>Builder.SetElementControlIdentifier(prop, ControlIdentifiers<c> => </c>prop.SetInputControl(ControlIdentifiers</c> <c>Builder.SetPropertyHeightInPixels(prop, 200);<c> => </c>prop.SetHeightInPixels(200);</c> </ul> Constructing a module has also changed. Instead of using the following syntax, <code> var module = Builder.SetUpForModule<auditmodule>(Name, "ApexClearing.Alps.Core", Name, true); </code> Replace it with the following direct replacement, <code> var module = Builder.CreateModule(Name, "ApexClearing.Alps.Core", Name); </code> Or use this replacement, with the recommended style for the v2 format (no more class prefix for generated classes and a standard namespace): <code> var module = Builder.CreateModule(Name, typeof(AuditModuleBuilder).GetParentNamespace()); </code> <h level="3">Standard Modules (e.g. Reporting, Security, etc.)</h> Because of how the module class-names have changed, the standard module ORM classes all have different names. The formula is that the ORM class-name is no longer prepended its module name. <ul> <c>ReportsReportDefinition</c> => <c>ReportDefinition</c> <c>SecurityUser</c> => <c>User</c> And so on... </ul> Furthermore, all modules have been converted to use the v2 code-generation format, which has the metadata separate from the ORM object. Therefore, instead of referencing metadata using the ORM class-name as the base, you use the module name as the base. <ul> <c>ReportReportDefinition.Fields.Name</c> => <c>ReportModule.ReportDefinition.Name.Identifier</c> <c>ReportReportDefinition.MetaProperties.Name</c> => <c>ReportModule.ReportDefinition.Name</c> <c>ReportReportDefinition.Metadata</c> => <c>ReportModule.ReportDefinition.Metadata</c> And so on... </ul> There's an upcoming article that will show more examples of the improved flexibility and capabilities that come with the v2-metadata. <h level="3">Action names</h> The standard action names have moved as well. <ul> ActionNames => ApplicationActionNames MetaActionNames => MetaApplicationActionNames </ul> Any other, more rarely used action names have been moved back to the actions themselves, so for example <code> SaveApplicationSettingsAction.ActionName </code> If you created any actions of your own, then the API there has changed as well. As previously documented in <a href="{app}view_article.php?id=426">API Design: To Generic or not Generic? (Part II)</a>, instead of overriding the following method, <code> protected override int DoExecute(IApplication application, ConfigurationOptions options, int currentResult) { base.DoExecute(application, options, currentResult); } </code> you instead override in the following way, <code> public override void Execute() { base.Execute(); } </code> <h level="3">Using NuGet</h> If you're already using Visual Studio 2015, then the NuGet UI is a good choice for managing packages. If you're still on Visual Studio 2013, then the UI there is pretty flaky and we recommend using the console. The examples below assume that you have configured a source called "Local Quino" (e.g. a local folder that holds the <c>nupkg</c> files for Quino). <code> install-package Quino.Data.PostgreSql.Testing -ProjectName Punchclock.Core.Tests -Source "Local Quino" install-package Quino.Server -ProjectName Punchclock.Server -Source "Local Quino" install-package Quino.Console -ProjectName Punchclock.Server -Source "Local Quino" install-package Quino.Web -ProjectName Punchclock.Web.API -Source "Local Quino" </code> <h level="3">Debugging Support</h> We recommend using Visual Studio 2015 if at all possible. Visual Studio 2013 is also supported, but we have all migrated to 2015 and our knowhow about 2013 and its debugging idiosyncrasies will deteriorate with time. These are just brief points of interest to get you set up. As with the NuGet support, these instructions are subject to change as we gain more experience with debugging with packages as well. <ul> Hook up to a working symbol-source server (e.g. TeamCity) Get the local sources for your version If you don't have a source server or it's flaky, then get the PDBs for the Quino version you're using (provided in <c>Quino.zip</c> as part of the package release) Add the path to the PDBs to your list of symbol sources in the VS debugging options Tell Visual Studio where the sources are when it asks during debugging Tell R# how to map from the source folder (c:\BuildAgent\work\9a1bb0adebb73b1f for Quino 2.0.0-1765) to the location of your sources </ul> Quino packages are no different than any other NuGet packages. We provide both standard packages as well as packages with symbols and sources. Any complications you encounter with them are due to the whole NuGet experience still being a bit in-flux in the .NET world. An upcoming post will provide more detail and examples. <h level="3">Creating Nuget Packages</h> We generally use our continuous integration server to create packages, but you can also create packages locally (it's up to you to make sure the version number makes sense, so be careful). These instructions are approximate and are subject to change. I provide them here to give you an idea of how packages are created. If they don't work, please contact Encodo for help. <ul> Open PowerShell Change to the <c>%QUINO_ROOT%\src</c> directory Run <c>nant build pack</c> to build Quino and packages Set up a local NuGet Source name "Local Quino" to <c>%QUINO_ROOT%\nuget</c> (one-time only) Change to the directory where your Quino packages are installed for your solution. Delete all of the Encodo/Quino packages Execute <c>nant nuget</c> from your project directory to get the latest Quino build from your local folder </ul>