9

After spending countless of hours on getting to the core of a bug, I eventually boiled down a problem to the use of string.Compare with StringComparison.InvariantCultureIgnoreCase in .NET 5.

Consider the following two dotnetfiddles:

When running the .NET 4.7.2 you get -1 as a result, when running .NET 5 you get 1 as a result.

After some browsing, this led to the following notice:

So, going by this, a result of -1 is the NLS version, whereas the .NET 5 result of 1 is the ICU version.

However, when I spin up an Azure App Service in .NET 5 mode, the result of the above code in a Razor page is -1, AKA: the NLS version.

This can cause all kinds of weird issues, because two different systems lead to unexpected results.

When I add add the following to my project-file, as mentioned in the last article, my local environment also outputs a -1.

<ItemGroup>
  <RuntimeHostConfigurationOption Include="System.Globalization.UseNls" Value="true" />
</ItemGroup>

No matter what kind of configuration I use in Azure, it will always keep outputting -1.

Long story, something is up on Azure. As per documentation, my Windows version is new enough to have ICU enabled. Looks like the Azure App Service is either using a forced NLS mode, or is running some ICU version my local machine doesn't have.

Anyone know how I can figure out which ICU version (if any) Azure is using, so I can use the suggestion from the documentation to use a AppLocalIcu? Otherwise, if something is clearly on the side of Azure, then my question is what the best location would be to report this?

Lennard Fonteijn
  • 2,561
  • 2
  • 24
  • 39
  • I would take this to github and get an authoritative answer, and if there is a bug they will likely fix it, or put open for others to fix and do a pull request – TheGeneral Sep 01 '21 at 01:20
  • @TheGeneral Which GitHub would be the most appropriate for that? I contemplated using the dotnet one, but it seems like this is an Azure issue, not .NET itself. – Lennard Fonteijn Sep 02 '21 at 11:38

2 Answers2

7

Someone at the Azure App Service team dove into this:

  • Most Azure App Services run on Windows 2016, more specifically at the time of writing:
Major  Minor  Build  Revision
-----  -----  -----  --------
10     0      14393  0   
  • In the Windows Server landscape ICU was introduced in Windows Server 2019.

So to answer my own question: Azure App Services are indeed using NLS by default. This is not a bug!

By including the following in your project-file, ICU will be forced:

<ItemGroup Condition="'$(OS)' == 'Windows_NT'">
  <PackageReference Include="Microsoft.ICU.ICU4C.Runtime" Version="68.2.0.9" />
  <RuntimeHostConfigurationOption Include="System.Globalization.AppLocalIcu" Value="68.2" />
</ItemGroup>

This is in line with the solution that @Crazy Crab mentioned, thanks!

Also see https://www.nuget.org/packages/Microsoft.ICU.ICU4C.Runtime for the latest version (68.2.0.9 at the time of writing).

I'm going to accept my own answer, as I feel it gives a better answer to the "Why is this happening" question, rather than just fixing it.

Lennard Fonteijn
  • 2,561
  • 2
  • 24
  • 39
  • 2
    FYI still appears to be the case -- ran into this issue ourselves today on an Azure App Service. – IGx89 Apr 21 '22 at 22:18
  • 1
    Super helpful answer. One consideration: If you're building on a linux host (e.g. github actions), you should remove that `Condition` on the `ItemGroup`. – Donnie Hale Aug 28 '23 at 16:45
3

I think you can use this method to enable the App-local ICU in the Azure app service.

If your web app is a framework-dependent application, you can consume ICU via a NuGet package.

  • Install the NuGet package Microsoft.ICU.ICU4C.Runtime in your web app project.
  • Edit the project file to add <RuntimeHostConfigurationOption Include="System.Globalization.AppLocalIcu" Value="<suffix>:<version> or <version>" /> in the section <ItemGroup>. Or you can add an app setting DOTNET_SYSTEM_GLOBALIZATION_APPLOCALICU with the value <suffix>:<version> or <version>.

Then you can use the special version of ICU in the Azure App Service as you want.

Crazy Crab
  • 694
  • 6
  • 16