Skip to main content

Enabling Globalization Invariant Mode for .NET Core App on Raspberry Pi Running LibreElec

I had an app I wanted to run on my Raspberry Pi 3 running LibreElec. In LibreElec you can install the dotnet core 2.2 runtime as an addon, and in Visual Studio you can compile for ARM processors with ‘Target Runtime’ set to ‘linux-arm’ in the publish profile. So, I published to a folder from VS using that profile, and I copied the output over to my RPi which had the dotnet runtime installed. I did a simple dotnet Whatever.dll to run the app (actually in this case, it was /storage/.kodi/addons/tools.dotnet-runtime/bin/dotnet Whatever.dll because of the way the addon is installed) and was met with this error:

FailFast:
Couldn't find a valid ICU package installed on the system. Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support.

   at System.Environment.FailFast(System.String)
   at System.Globalization.GlobalizationMode.GetGlobalizationInvariantMode()
   at System.Globalization.GlobalizationMode..cctor()
   at System.Globalization.CultureData.CreateCultureWithInvariantData()
   at System.Globalization.CultureData.get_Invariant()
   at System.Globalization.CultureInfo..cctor()
   at System.StringComparer..cctor()
   at System.AppDomain.InitializeCompatibilityFlags()
   at System.AppDomain.CreateAppDomainManager()
   at System.AppDomain.Setup(System.Object)
Aborted

What’s happening here is that .NET Core relies on ICU for globalization. On Linux, if the ICU binary is not present (which is the case with LibreElec), the application will fail to start. To resolve the issue you either need to install ICU on the system or turn off globalization with the runtime configuration options for globalization. Since I wasn’t interested in trying to compile ICU for LibreEelec (there are no binaries ready-to-go), I chose the latter.

Rather than set the DOTNET_SYSTEM_GLOBALIZATION_INVARIANT environment variable, I wanted to modify the Whatever.runtimeconfig.json file. There are two ways to do this automatically at publish-time:

  • Set an option in the project file, like this

    <ItemGroup>
     <RuntimeHostConfigurationOption Include="System.Globalization.Invariant" Value="true" />
    </ItemGroup>
    
  • Add a runtimeconfig.template.json file with the properties you want included by default, like this

    {
     "configProperties": {
      "System.Globalization.Invariant": true
     }
    }
    

I tested both, and ultimately selected the first method. Before enabling globalization invariant mode, my runtimeconfig.json looked like this:

{
  "runtimeOptions": {
    "configProperties": {
      "System.GC.Server": true
    }
  }
}

Afterward, it looked like this:

{
  "runtimeOptions": {
    "configProperties": {
      "System.Globalization.Invariant": true,
      "System.GC.Server": true
    }
  }
}

Hat tip to this issue which is one of the top results when you Google the specific error message.

Comments

Popular posts from this blog

Who I'm Is

I am a junior .NET developer currently working in Chicago, IL. I am starting this blog in order to enhance my knowledge of programming subject matter. Hopefully, someone else will be helped along the way. This first post will probably be edited soon...

Stubbing Static Methods with PostSharp

TypeMock uses the Profiler API to allow mocking, stubbing, etc. of classes used by code under test. It has the ability to handle sealed classes, static classes, non-virtual methods, and other troublesome-yet-oft-encountered scenarios in the world of unit testing. Other frameworks rely on proxies to intercept method calls, limiting them to be able to only fake virtual, abstract, and interface members. They also rely on dependecy injection to place the proxies as the concrete implementation of calls to the abstracted interface members. Anyone working with a legacy codebase is bound to run into static method calls (especially in the data access layer), dependencies on concrete types with non-virtual methods, and sealed class dependencies (HttpContext anyone?). The only way to unit test this without refactoring is with TypeMock. I've never used TypeMock, and I'm sure it's a great product, but it's not free. I decided to spike some code to see if I could solve the prob...

Strongly-Typed Property Constraints in Rhino Mocks

UPDATE: As I suspected, this functionality was right in front of my face – it’s called PredicateConstraint in Rhino Mocks. I also realize that I managed to completely ignore the existence of Predicate<T> in the framework, and write my own predicate delegate. Hey, I was on a roll. Rhino Mocks has a PropertyConstraint class that allows you to check the values on properties of objects passed into the method as part of the verification for that method being called. Unfortunately, the name of the property is specified as a string, which means the benefits of strong-typing that Rhino Mocks is normally so good at preserving are lost. Here’s an example (using Rhino Mocks 3.3 and .NET 2.0): [Test] public void Main_Form_Should_Show_Start_Panel_On_Load() { MockRepository mockRepository = new MockRepository(); IMainFormView mockView = mockRepository.DynamicMock<IMainFormView>(); IEventRaiser loadEventRaiser = GetEventRaiserFor(delegate { mockView.Load += null; });...