Quino v8.0.0: ASP.NET Core, Web Client 2, Culture/Language improvements
Published by marco on
The summary below describes major new features, items of note and breaking changes.
- Resources
- Artifacts (Note: the URL is a NuGet Source; you can’t browse here directly)
- Documentation
Issues/Changelog
The links above require a login.
Highlights
- Quino-Web now targets ASP.NET Core (QNOWEB-149, QNOWEB-84, QNOWEB-55)
- Quino-Web has Serilog enabled by default (QNOWEB-147, QNOWEB-146, QNOWEB-145, QNOWEB-139)
- Enabled SourceLink for all packages (QNOWIN-262)
- Improved testing and debugging support. (QNO-6289, QNO-6282, QNO-6278, QNO-6277, QNO-6275, QNO-6255, QNO-6213)
- Improved culture and language-handling (QNO-6302, QNO-6303, QNO-6253, QNO-6230, QNO-6228)
- Extended expression functions with
CreateGuid()
,CreateDate()
, andCreateTime()
. (QNO-6304, QNO-6305)
Breaking Changes
Before upgrading, products should make sure that they do not depend on any obsolete members in the current version (7.x).
ASP.NET Core
Quino-Web 8.0 is a rewrite and is therefore mostly incompatible with 7.x.
- The controller returns data in a completely different format
- The Quino Client has been completely rewritten to accommodate it
- The startup and pipeline have been completely rewritten to integrate with ASP.NET Core
- Testing support has been considerably extended to accommodate end-to-end integration testing and in-process hosts
See the Quino-Web/Sandbox.Web
project for a working example. This integrates the standard SandboxApplication
into a web site using the standard GenericController
and MetadataController
to provide data and UI to the generic Quino Client.
Namespace Changes
Some internal types in Quino-Standard have been moved to more appropriate namespaces and assemblies, but the impact on products should be non-existent or very limited.
The following types were moved from Encodo.Quino.Core
to Encodo.Quino.Culture
:
LanguageTextAttribute
IValueParser
CaptionAttribute
LanguageDescriptionAttribute
The following types were moved from Encodo.Quino.Core
to Encodo.Quino.TextFormatting
:
* IFileSizeFormatter
Culture- and Language-Handling
Quino’s default culture-handling has been overhauled. Instead of tracking its own language, Quino now uses the standard .NET CultureInfo.CurrentUICulture
for the default language and CultureInfo.CurrentCulture
for default formatting (e.g. times, dates, and currencies). Many fields have been marked as obsolete and are no longer used by Quino.
Default Languages
The default languages in Quino have changed from “en-US” and “de-CH” to “en and “de”, respectively.
The reasoning behind this is that, while a _requested language_ should be as specific as possible, a _supported language_ should be as general as possible. The standard culture mechanisms and behavior (e.g. .NET Resources) “fall back” to a parent language when a more-specific language cannot be found. If an application claims to only support “en-US”, then a request for “en-GB” fails. If the supported language is “en”, then any request to a language in the “en” family (e.g. “en-US”, “en-GB”, “en-AU”) will use “en”.
An application that supports “en-US” and “de-CH” has, therefore, a more limited palette of languages that it can support.
Fallback-resolution
Quino code runs in the context of a user, who has a list of preferred languages, in decreasing order of preference. This context can last the entire duration of an application (e.g. a standalone application like a console or desktop application) or last as long as a web request.
The application itself has a list of languages that it supports, as well as resources and metadata that defines text in these languages. The resources are standard .NET Resources with the standard fallback mechanism (i.e. a request for “en-US” can be satisfied by “en”). The metadata uses DynamicString
objects, which encapsulate a map from language codes (e.g. “en” or “de”) to strings.
During application startup or at the beginning of a web request, the ILanguageResolver
determines the language to use for a given set of requested languages. In ASP.NET Core, the requested languages come from the HTTP headers provided by the browser. In standalone applications, the IRequestedLanguageCalculator
provides the requested languages. The ILanguageInitializer
is responsible for coordinating this during application startup.
The rest of Quino uses the following singletons to work with languages.
IDynamicStringFallbackCalculator
: Comes into play when a request is made for a language that is not directly supported. For example, if the application supports “en” and “de”, then a request for “en-US” will ask this singleton how to resolve the request.IDynamicStringFactory
: Creates a dynamic string to describe a given object. The default implementation uses .NET Attributes.ILanguageResolver
: Determines the culture to use from a list of available cultures and a list of requested/preferred cultures.IRequestedLanguageCalculator
: Provides the sequence of languages from which to choose during initial resolution (web requests _do not_ use this).ILanguageInitializer
: Integrates language-selection into the application startup.ICaptionCalculator
: Extracts a single caption for a culture from a given object. Appications should use theIDynamicStringFactory
in most cases, instead.
An application can control fallback by registering custom IDynamicStringFallbackCalculator
and ILanguageResolver
implementations (though this is almost certainly not necessary).
Opting in or out
Any product that calls AddEnglishAndGerman()
will automatically be upgraded as well. A product can avoid this change by calling AddAmericanEnglishAndSwissGerman()
instead.
Reports
A product that uses the new languages will have to replace all fields in reports targeted at “en-US” and “de-CH” to target “en” and “de” instead.
Database Fields
A product that does use the new default languages will have to determine how to migrate database fields created for languages that are no longer explicitly supported. If the model includes value-lists (enums) or multi-language properties , the application will have to migrate the database schema to update multi-language fields (e.g. “caption_en_us” => “caption_en”).
Manual MetaIds
A product that sets MetaIds
manually will migrate without modification (Quino will rename the property in the database).
Automatic MetaIds
A product that does _not_ set MetaIds
(this has been the default in Quino since version 2) will have a MetaID mismatch because the name has changed.
By default, Quino will migrate by attempting to drop, then re-create multi-language properties. In the case of value-list captions, this is harmless (since the data stored in these tables are generated wholly from the metadata). For actual multi-language properties with user data in them, this is _a problem_.
The simple solution is to call UseLegacyLanguageMappingFinalizerBuilder()
during application configuration to ensure a smooth migration (Quino will rename the property in the database).
Regenerating Code
A product that updates its languages should regenerate code to update any generated language-specific properties. Properties that had previously been generated as, e.g. Caption_en_us
will now be Caption_en
.