Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.NET misreports current culture after upgrading to .NET6 #60296

Closed
Joren-Thijs opened this issue Oct 11, 2021 · 14 comments
Closed

.NET misreports current culture after upgrading to .NET6 #60296

Joren-Thijs opened this issue Oct 11, 2021 · 14 comments
Labels
area-System.Globalization needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration
Milestone

Comments

@Joren-Thijs
Copy link

  • .NET Core Version: 6.0.100-rc.1.21463.6
  • Windows version: 21H1 (OS Build 19043.1237)
  • Does the bug reproduce also in WPF for .NET Framework 4.8: No
  • Is this bug related specifically to tooling in Visual Studio? No

Problem description:

After upgrading from .NET 5.0.4 to .NET6 RC1 I run into a {"Culture is not supported. (Parameter 'culture')\r\n4096 (0x1000) is an invalid culture identifier."} exception. The culture reported here is en-be (English-Belgium) which of course does not exist.
.NET is misreporting the current UI culture. My app is set to English, my Windows 10 is set to English, my keyboard is set to English (US International) but my region is set to Belgium where i live.

Expected behavior:

.NET accurately identifies the culture info is either en-us or something that matches my locale.
Note I do not have my native and regional language Dutch (be-nl) installed on this machine, nor have I had it installed on this machine before.
I only have en-us installed on my windows machine.

@Joren-Thijs
Copy link
Author

Yes it is easily fixed by adding

System.Globalization.CultureInfo.CurrentCulture = new System.Globalization.CultureInfo("en-US");
System.Globalization.CultureInfo.CurrentUICulture = new System.Globalization.CultureInfo("en-US");

to my app's startup method but it shouldn't be necesarry and .NET should not be making up UI cultures that do not exist.

@ryalanms
Copy link
Member

ryalanms commented Oct 11, 2021

@benvillalobos: Can you take a look? This may be related to dotnet/wpf#5381.

@singhashish-wpf singhashish-wpf transferred this issue from dotnet/wpf Oct 12, 2021
@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.Globalization untriaged New issue has not been triaged by the area owner labels Oct 12, 2021
@ghost
Copy link

ghost commented Oct 12, 2021

Tagging subscribers to this area: @tarekgh, @safern
See info in area-owners.md if you want to be subscribed.

Issue Details
  • .NET Core Version: 6.0.100-rc.1.21463.6
  • Windows version: 21H1 (OS Build 19043.1237)
  • Does the bug reproduce also in WPF for .NET Framework 4.8: No
  • Is this bug related specifically to tooling in Visual Studio? No

Problem description:

After upgrading from .NET 5.0.4 to .NET6 RC1 I run into a {"Culture is not supported. (Parameter 'culture')\r\n4096 (0x1000) is an invalid culture identifier."} exception. The culture reported here is en-be (English-Belgium) which of course does not exist.
.NET is misreporting the current UI culture. My app is set to English, my Windows 10 is set to English, my keyboard is set to English (US International) but my region is set to Belgium where i live.

Expected behavior:

.NET accurately identifies the culture info is either en-us or something that matches my locale.
Note I do not have my native and regional language Dutch (be-nl) installed on this machine, nor have I had it installed on this machine before.
I only have en-us installed on my windows machine.

Author: Joren-Thijs
Assignees: -
Labels:

area-System.Globalization, untriaged

Milestone: -

@ghost ghost added this to Untriaged in ML, Extensions, Globalization, etc, POD. Oct 12, 2021
@tarekgh
Copy link
Member

tarekgh commented Oct 12, 2021

@Joren-Thijs if you create a simple console app doing

Console.WriteLine(CultureInfo.CurrentCulture)
Console.WriteLine(CultureInfo.CurrentUICulture)

Compile and run it against .NET 5.0 and .NET 6.0 on same machine, are you getting different results?

We are reading the UI culture from Windows and we didn't change this part. Also, could you please share the full stack of the exception you are getting?

CC @safern

@tarekgh tarekgh added needs more info and removed untriaged New issue has not been triaged by the area owner labels Oct 12, 2021
@tarekgh tarekgh added this to the 7.0.0 milestone Oct 12, 2021
@ghost ghost moved this from Untriaged to 7.0.0 in ML, Extensions, Globalization, etc, POD. Oct 12, 2021
@tarekgh
Copy link
Member

tarekgh commented Oct 12, 2021

I have mimicked the same settings mentioned by @Joren-Thijs and run the following code on both .NET 5.0 and .NET 6.0. I set the UI and user locales on the machine as en-US and set the region to Belgium.

    Console.WriteLine($"CurrentCulture   = {CultureInfo.CurrentCulture.Name}");
    Console.WriteLine($"CurrentUICulture = {CultureInfo.CurrentUICulture.Name}");
    Console.WriteLine($"{RegionInfo.CurrentRegion}");

and I am getting the exact same results on both cases:

CurrentCulture   = en-US
CurrentUICulture = en-US
BE

@singhashish-wpf This looks more a WPF issue than the runtime issue. Did you have a chance to look at?

@Joren-Thijs
Copy link
Author

Joren-Thijs commented Oct 12, 2021

Culture issue

@tarekgh I have done what you asked and run the same code in both .net 5 and .net 6

using System;
using System.Globalization;

namespace CultureTest
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine($"CurrentCulture   = {CultureInfo.CurrentCulture.Name}");
            Console.WriteLine($"CurrentUICulture = {CultureInfo.CurrentUICulture.Name}");
            Console.WriteLine($"{RegionInfo.CurrentRegion}");
        }
    }
}

In both cases it yields the same output:

CurrentCulture   = en-BE
CurrentUICulture = en-US
BE

So it appears there's either a deeper issue or a very isolated issue with my machine?

I am once again going to include my system info below:

Device Specifications
Device name	MSI
Processor	Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz   2.80 GHz
Installed RAM	16,0 GB (15,9 GB usable)
Device ID	7047433C-982A-4F62-8CF4-E4A32C188353
Product ID	00325-96167-21272-AAOEM
System type	64-bit operating system, x64-based processor
Pen and touch	No pen or touch input is available for this display
Windows Specifications
Edition	Windows 10 Home
Version	21H1
Installed on	‎29/‎06/‎2021
OS build	19043.1237
Experience	Windows Feature Experience Pack 120.2212.3530.0

My language settings:

image

Here under language settings i do see that my systems app language is English (Belgium) but i did not set this specifically.
Nor do I understand why .net 5 allows en-BE but .net 6 does not?

Dotnet 5 info
.NET SDK (reflecting any global.json):
 Version:   5.0.401
 Commit:    4bef5f3dbf

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.19043
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\5.0.401\

Host (useful for support):
  Version: 6.0.0-rc.1.21451.13
  Commit:  d7619cd4b1

.NET SDKs installed:
  5.0.401 [C:\Program Files\dotnet\sdk]
  6.0.100-preview.6.21355.2 [C:\Program Files\dotnet\sdk]
  6.0.100-rc.1.21463.6 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 3.1.19 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.10 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.0-preview.6.21355.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.0-rc.1.21452.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.10 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.19 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.10 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.0-preview.6.21352.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.0-rc.1.21451.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.10 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.19 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.10 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.0-preview.6.21353.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.0-rc.1.21451.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Dotnet 6 info
.NET SDK (reflecting any global.json):
 Version:   6.0.100-rc.1.21463.6
 Commit:    e627d556a1

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.19043
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\6.0.100-rc.1.21463.6\

Host (useful for support):
  Version: 6.0.0-rc.1.21451.13
  Commit:  d7619cd4b1

.NET SDKs installed:
  5.0.401 [C:\Program Files\dotnet\sdk]
  6.0.100-preview.6.21355.2 [C:\Program Files\dotnet\sdk]
  6.0.100-rc.1.21463.6 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 3.1.19 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.10 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.0-preview.6.21355.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.0-rc.1.21452.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.10 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.19 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.10 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.0-preview.6.21352.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.0-rc.1.21451.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.10 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.19 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.10 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.0-preview.6.21353.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.0-rc.1.21451.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

WPF

However I cannot answer why my WPF project only crashes on .NET 6 since the method that throws was a constructor for a CSV parser from this Filehelpers libary. (I have the latest version 3.5 installed)
image

This method does not throw in .NET 5 which i find odd, even though it appears both .NET 5 and 6 misreport my current culture

I have also grabbed the full exception from my log files:

2021-10-12 21:54:23.202 +02:00 [ERR] Prism.Regions.ViewRegistrationException: An exception has occurred while trying to add a view to region 'ContentRegion'. 
    - The most likely causing exception was was: 'System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.Windows.Markup.XamlParseException: 'Set property 'Prism.Mvvm.ViewModelLocator.AutoWireViewModel' threw an exception.' Line number '9' and line position '5'.
 ---> Prism.Ioc.ContainerResolutionException: An unexpected error occurred while resolving 'MachineViewer.Core.UI.WPF.ProductSettingsViewModel'
 ---> Unity.ResolutionFailedException: Resolution failed with error: Exception has been thrown by the target of an invocation.

For more detailed information run Unity in debug mode: new UnityContainer().AddExtension(new Diagnostic())
 ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.Globalization.CultureNotFoundException: Culture is not supported. (Parameter 'culture')
4096 (0x1000) is an invalid culture identifier.
   at System.Globalization.CultureInfo..ctor(Int32 culture, Boolean useUserOverride)
   at System.Globalization.CultureInfo..ctor(Int32 culture)
   at FileHelpers.Converters.CultureConverter.CreateCulture(String decimalSepOrCultureName)
   at FileHelpers.Converters.CultureConverter..ctor(Type T, String decimalSepOrCultureName)
   at FileHelpers.Converters.Int32Converter..ctor(String decimalSepOrCultureName)
   at FileHelpers.Converters.ConvertHelpers.GetDefaultConverter(String fieldName, Type fieldType, String defaultCultureName)
   at FileHelpers.FieldBase..ctor(FieldInfo fi, String defaultCultureName)
   at FileHelpers.DelimitedField..ctor(FieldInfo fi, String sep, String defaultCultureName)
   at FileHelpers.FieldBase.CreateField(FieldInfo fi, TypedRecordAttribute recordAttribute)
   at FileHelpers.RecordInfo.CreateCoreFields(IList`1 fields, TypedRecordAttribute recordAttribute)
   at FileHelpers.RecordInfo.InitRecordFields()
   at FileHelpers.RecordInfo..ctor(Type recordType)
   at FileHelpers.RecordInfo.RecordInfoFactory.Resolve(Type type)
   at FileHelpers.RecordInfo.Resolve(Type type)
   at FileHelpers.EngineBase..ctor(Type recordType, Encoding encoding)
   at FileHelpers.EventEngineBase`1..ctor(Type recordType, Encoding encoding)
   at FileHelpers.FileHelperEngine`1..ctor(Type recordType, Encoding encoding)
   at FileHelpers.FileHelperEngine..ctor(Type recordType, Encoding encoding)
   at FileHelpers.FileHelperEngine..ctor(Type recordType)
   at MachineViewer.Core.GenericRecipeParser`1..ctor(IRecipeService recipeService) in D:\repos\CTESO\Machine_Viewer\src\Core\MachineViewer.Core\Recipes\GenericRecipeParser.cs:line 20
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Unity.Processors.ConstructorProcessor.<>c__DisplayClass16_0.<GetResolverDelegate>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.UnityContainer.<>c__DisplayClass113_0.<OptimizingFactory>b__0(BuilderContext& c)
   at Unity.Strategies.BuildPlanStrategy.PreBuildUp(BuilderContext& context)
   at Unity.UnityContainer.<>c.<.ctor>b__73_2(BuilderStrategy[] chain, BuilderContext& context)
   at Unity.Builder.BuilderContext.Resolve(Type type, String name, InternalRegistration registration)
   at Unity.Builder.BuilderContext.Resolve(Type type, String name)
   at Unity.Builder.BuilderContext.Resolve(ParameterInfo parameter, Object value)
   at Unity.Processors.ParametersProcessor`1.<>c__DisplayClass7_0.<CreateParameterResolvers>b__0(BuilderContext& context)
   at Unity.Processors.ConstructorProcessor.<>c__DisplayClass16_0.<GetResolverDelegate>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.UnityContainer.<>c__DisplayClass113_0.<OptimizingFactory>b__0(BuilderContext& c)
   at Unity.Strategies.BuildPlanStrategy.PreBuildUp(BuilderContext& context)
   at Unity.UnityContainer.<>c.<.ctor>b__73_2(BuilderStrategy[] chain, BuilderContext& context)
   at Unity.Builder.BuilderContext.Resolve(Type type, String name, InternalRegistration registration)
   at Unity.Builder.BuilderContext.Resolve(Type type, String name)
   at Unity.Builder.BuilderContext.Resolve(ParameterInfo parameter, Object value)
   at Unity.Processors.ParametersProcessor`1.<>c__DisplayClass7_0.<CreateParameterResolvers>b__0(BuilderContext& context)
   at Unity.Processors.ConstructorProcessor.<>c__DisplayClass16_0.<GetResolverDelegate>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.UnityContainer.<>c__DisplayClass113_0.<OptimizingFactory>b__0(BuilderContext& c)
   at Unity.Strategies.BuildPlanStrategy.PreBuildUp(BuilderContext& context)
   at Unity.UnityContainer.<>c.<.ctor>b__73_1(BuilderContext& context)
   --- End of inner exception stack trace ---
   at Unity.UnityContainer.<>c.<.ctor>b__73_1(BuilderContext& context)
   at Unity.UnityContainer.Unity.IUnityContainer.Resolve(Type type, String name, ResolverOverride[] overrides)
   at Prism.Unity.UnityContainerExtension.Resolve(Type type, ValueTuple`2[] parameters)
   --- End of inner exception stack trace ---
   at Prism.Unity.UnityContainerExtension.Resolve(Type type, ValueTuple`2[] parameters)
   at Prism.Unity.UnityContainerExtension.Resolve(Type type)
   at Prism.PrismInitializationExtensions.<>c.<ConfigureViewModelLocator>b__0_0(Object view, Type type)
   at Prism.Mvvm.ViewModelLocationProvider.AutoWireViewModelChanged(Object view, Action`2 setDataContextCallback)
   at Prism.Mvvm.ViewModelLocator.AutoWireViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
   at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
   at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)
   at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
   at System.Windows.Baml2006.WpfMemberInvoker.SetValue(Object instance, Object value)
   at MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetValue(Object inst, XamlMember property, Object value)
   --- End of inner exception stack trace ---
   at System.Windows.Markup.XamlReader.RewrapException(Exception e, IXamlLineInfo lineInfo, Uri baseUri)
   at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
   at System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
   at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
   at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
   at MachineViewer.Core.UI.WPF.ProductSettings.InitializeComponent() in D:\repos\CTESO\Machine_Viewer\src\Core\MachineViewer.Core.UI.WPF\Pages\ProductSettings\ProductSettings.xaml:line 1
   at MachineViewer.Core.UI.WPF.ProductSettings..ctor(ILocalizationService localizationService) in D:\repos\CTESO\Machine_Viewer\src\Core\MachineViewer.Core.UI.WPF\Pages\ProductSettings\ProductSettings.xaml.cs:line 13
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Unity.Processors.ConstructorProcessor.<>c__DisplayClass16_0.<GetResolverDelegate>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.UnityContainer.<>c__DisplayClass113_0.<OptimizingFactory>b__0(BuilderContext& c)
   at Unity.Strategies.BuildPlanStrategy.PreBuildUp(BuilderContext& context)
   at Unity.UnityContainer.<>c.<.ctor>b__73_1(BuilderContext& context)'.
    But also check the InnerExceptions for more detail or call .GetRootException(). 
 ---> Prism.Ioc.ContainerResolutionException: An unexpected error occurred while resolving 'MachineViewer.Core.UI.WPF.ProductSettings'
 ---> Unity.ResolutionFailedException: Resolution failed with error: Exception has been thrown by the target of an invocation.

@ghost ghost added needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration and removed needs more info labels Oct 12, 2021
@Joren-Thijs
Copy link
Author

Update: so i tried switching my app language in windows to en-US and now the reported culture is indeed en-US
So i was wrong to assume .NET was misreporting it. My apologies.
image

CurrentCulture   = en-US
CurrentUICulture = en-US
BE

That just leaves me with the question why that code did not throw in net 5 but did throw in net 6? since i can manually set the culture to en-BE without .net crashing on me in my sample app.

I'm going to investigate the library code and see if I can find any issues there.

For now I am going to close this issue. If i find anything i will report it here.

ML, Extensions, Globalization, etc, POD. automation moved this from 7.0.0 to Done Oct 12, 2021
@tarekgh
Copy link
Member

tarekgh commented Oct 12, 2021

Thanks @Joren-Thijs for the info. I am seeing throwing on such case is the correct behavior. I am not sure either why this is not throwing on .NET 5.0. Something you may try is to print the value CultureInfo.CurrentCulture.LCID on both cases and look if you see a difference. Anyway, I am seeing FileHelpers.Converters.CultureConverter.CreateCulture has a problem to blindly trying to create a culture with LCID value which can throw as you get in your case. Our guidelines are always use culture names to create cultures and stay away from LCID's as these obsolete and causes a lot of problems because Windows report many cultures with the same LCID value 0x1000.

@tarekgh
Copy link
Member

tarekgh commented Oct 12, 2021

Here is the line that need to be fixed:

https://github.com/MarcosMeli/FileHelpers/blob/ecdeac468033b36de61bf7ab0bcb826113d6ca5b/FileHelpers/Converters/CultureConverter.cs#L61

This can be fixed by the code like:

    ci = new CultureInfo(CultureInfo.CurrentCulture.Name);

@Joren-Thijs
Copy link
Author

Wow thats a lot of great info! Thank you!

@Joren-Thijs
Copy link
Author

@tarekgh I have done some additional testing and did find a descrepancy between .net 5 en .net 6

When printing out the LCID for en-BE in net 5 it returns 8192 but in net 6 it returns 4096. While en-US returns 1033 for both net 5 and net 6.

Here is my new test code where i do print out the LCID:

using System;
using System.Globalization;

namespace CultureTest
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CultureInfo.CurrentCulture = new CultureInfo("en-US");
            Console.WriteLine($"CurrentCulture   = {CultureInfo.CurrentCulture.Name}");
            Console.WriteLine($"CurrentUICulture = {CultureInfo.CurrentUICulture.Name}");
            Console.WriteLine($"{RegionInfo.CurrentRegion}");
            Console.WriteLine($"{CultureInfo.CurrentCulture.LCID}");

            CultureInfo.CurrentCulture = new CultureInfo("en-BE");
            Console.WriteLine($"CurrentCulture   = {CultureInfo.CurrentCulture.Name}");
            Console.WriteLine($"CurrentUICulture = {CultureInfo.CurrentUICulture.Name}");
            Console.WriteLine($"{RegionInfo.CurrentRegion}");
            Console.WriteLine($"{CultureInfo.CurrentCulture.LCID}");

        }
    }
}

Net 5 output:

CurrentCulture   = en-US
CurrentUICulture = en-US
BE
1033
CurrentCulture   = en-BE
CurrentUICulture = en-US
BE
8192

Net 6 output:

CurrentCulture   = en-US
CurrentUICulture = en-US
BE
1033
CurrentCulture   = en-BE
CurrentUICulture = en-US
BE
4096

@tarekgh
Copy link
Member

tarekgh commented Oct 13, 2021

The behavior of .NET 6.0 is more correct. That is why we keep asking users to go away from LCID to avoid running into different issues.

To give more info why I am saying .NET 6.0 is the correct behavior. The case you are running into getting the LCID 8192 on .NET 5.0 for the culture en-BE because this LCID is temporary assigned LCID to that culture and depend on the machine configuration. If you have different configuration, you will get a different LCID like 4096 for the same culture. What this means? it means you cannot guarantee a stable LCID value across configurations which will be a big problem when running your app on different user's machines.
.NET 6.0 is consistent though returning 4096. If you review the protocol document MS-LCID - NET it is clearly states the following:

If the user has configured any of these locales without LCIDs in their Language Profile, then the system MAY assign them additional values to provide applications with temporary unique identifiers.

By the way, when I run your code on my machine with .NET 5.0 I am getting the following :-)

Microsoft Windows 10.0.22000
.NET 5.0.11

CurrentCulture   = en-US
CurrentUICulture = en-US
US
1033
CurrentCulture   = en-BE
CurrentUICulture = en-US
US
4096

@tarekgh tarekgh closed this as completed Oct 13, 2021
@Joren-Thijs
Copy link
Author

Again very useful info! Thank you!

@Joren-Thijs
Copy link
Author

Joren-Thijs commented Oct 13, 2021

@tarekgh I read the document you included and it's starting to make sense to me.
I am also going to quote the the full block of text for people briefly reading this, to provide more context.
Please let me know if I misunderstood anything😅

The LCID code is made up of three parts that together form a hex value. (See document)
image
image

But it also quotes:

Locale names that are valid but not associated with a given LCID MAY be assigned the LCID Language ID 0x1000,
if an LCID is demanded by the application. These include any valid [RFC5646] language tag.
Locales for which Windows can provide specific data appear in the following table;
however, any other name will be assigned the LCID Language ID 0x1000. 

If the user has configured any of these locales without LCIDs in their Language Profile,
then the system MAY assign them additional values to provide applications with temporary unique identifiers.

Those temporary LCIDs can differ between processes, machines, users, and application instances.
If a temporary LCID is assigned it will be 0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400,
0x3800, 0x3C00, 0x4000, 0x4400, 0x4800, or 0x4C00

For context for people reading this who like me don't convert hex values on the daily😅

tarekgh's code of 4096 translates to the default hex value of 0x1000. While my code of 8192 translates to 0x2000. Which is not out of spec (See quoted document) but a default value of 0x1000 is of course preferred. Therefore .NET 6 is more correct then .NET 5. (on my specific machine, on tarekgh's they both behave the same)

@ghost ghost locked as resolved and limited conversation to collaborators Nov 13, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Globalization needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration
Projects
None yet
Development

No branches or pull requests

3 participants