- Gepsio will ship as two assemblies, rather than a single assembly.
- Gepsio will no longer be able to support .NET 3.5 and will support only .NET 4.x.
This blog post will examine both of those changes and why they are necessary to be sacrificed to allow Gepsio to support UWP.
A Tale of Two Assemblies
Let’s first take a look at the need for Gepsio to be implemented in two assemblies, rather than just one as in the past.
Gepsio’s Use of String Resources
Gepsio not only parses XBRL
, but also validates the contents of an XBRL instance against the XBRL specification. Validation errors are available for inspection after the document instance is loaded, as in the following example:
var myDoc = new XbrlDocument();
if(myDoc.IsValid == false)
foreach(var currentValidationError in myDoc.ValidationErrors)
// the currentValidationError.Message property
// provides more information
// about the validation error
The messages are built into the Gepsio code base through a resource (RESX) file
. This RESX file, which is actually an XML document, contains the strings used to build the validation messages. Building these messages into a separate RESX file, rather than embedding them into the source code directly, allows the strings to be translated into various languages by providing a separate XML file for the new language, without having to change the source code itself. Since XBRL is an international specification, it makes sense to keep strings segregated where they can be easily located and changed when Gepsio needs to support languages other than English.
Microsoft changed the way string resources work for UWP assemblies. Resources are now stored in a RESW file, which has the same underlying XML structure as an RESX file but is incompatible with the tooling for .NET applications. Moreover, the code needed to access strings in an RESW file differs from the code needed to access strings in an RESX file.
Possible Design Approaches
The difference in approach between RESX files and RESW files impacts Gepsio, which strives to have a code base that supports .NET as well as UWP. There are several possible approaches to this problem, and they are described below.
One RESX for .NET, One RESW for UWP
With this approach, two resource files would be maintained: an RESX file for the .NET projects, and a RESW for the UWP project. This would cause a maintenance headache, as a developer working on Gepsio would have to remember that any strings added or modified in the RESX would have to be done again in the RESW file, and forgetting to do so will cause an incompatibility between Gepsio’s .NET implementation and its UWP implementation. If a string was found in one file and not the other, Gepsio may even crash at runtime when trying to find a string resource that doesn’t actually exist. Furthermore, since the code needed to access a string from an RESX file differs from the code needed to access a string from an RESW file, the code would also need to be maintained twice. Generally, making two modifications in two files can be more error-prone than making one modification in one file.
One RESX for .NET, Copied And Renamed for UWP
With this approach, one RESX file would be maintained in Gepsio’s .NET project, and a custom step in the build workflow would copy the RESX file over to the UWP project, rename it with an RESW extension, and allow the UWP project to build with the new RESW file. This approach would have the advantage of only needing to maintain one resource file. However, this would also introduce new complexities into the build process and would still require that two separate codebases be maintained: one to access the RESX file and another to access the RESW file.
Resources in a Portable Class Library
With this approach, the project would maintain a Portable Class Library (PCL) containing Gepsio’s string resources. The PCL would be targeted to support .NET as well as UWP. The PCL project would maintain the string resources as part of the project, as a single RESX file in a single location. The PCL would also contain code to access and return strings and Gepsio, in both its .NET and UWP personalities, would call this portable code when strings are needed.
Approach Going Forward
After considering all of the options (and lamenting the fact that the RESX/RESW discrepancy exists in the first place) it was decided to go down the PCL route. This means that, starting with the next release, Gepsio will ship as two assemblies:
- the main Gepsio assembly
- the Gepsio string resources assembly
The disadvantage here is that there are now two assemblies to distribute, rather than just the single assembly shipped up this point. The mitigation here is that distribution tools such as NuGet make distribution easier and more automatic, and the chances that a user would ship one Gepsio assembly and forget the other is reduced thanks to these tools.
The other disadvantage to the PCL approach leads us into the next change for the Gepsio platform.
End of Support for .NET 3.5
The “resources in PCL” approach described above signals the end of Gepsio’s support for .NET 3.5 and restricts Gepsio to supporting only .NET 4.0 and above. PCLs do not support .NET 3.5 and their support for .NET goes back only to .NET 4.0. This means that future versions of Gepsio will support the following platforms:
- .NET 4.0
- .NET 4.5
- .NET 4.5.1
- .NET 4.5.2
- .NET 4.6
- .NET 4.6.1
- Universal Windows
Though .NET 3.5 will be left off of this list, it is most likely not widely used these days. .NET 3.5 was released in November of 2007
and its replacement, .NET 4.0, was released in April of 2010
. It is therefore possible than any installations using .NET 3.5 at one time have been upgraded some time in the last six years to one of the .NET 4.x