Skip to content

Invariant mode breaking change #25305

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

Merged
merged 8 commits into from
Jul 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/core/compatibility/6.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ If you're migrating an app to .NET 6, the breaking changes listed here might aff
| [Standard numeric format parsing precision](core-libraries/6.0/numeric-format-parsing-handles-higher-precision.md) | Preview 2 |
| [Unhandled exceptions from a BackgroundService](core-libraries/6.0/hosting-exception-handling.md) | Preview 4 |

## Globalization

| Title | Preview introduced |
| - | - |
| [Culture creation and case mapping in globalization-invariant mode](globalization/6.0/culture-creation-invariant-mode.md) | Preview 7 |

## JIT compiler

| Title | Preview introduced |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,5 @@ Additionally, any class that depends on <xref:System.Char> to obtain the Unicode

- Core .NET libraries
- Globalization
-

-->
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
title: "Breaking change: Culture creation and case mapping in globalization-invariant mode"
description: Learn about the globalization breaking change in .NET 6 where the creation of new cultures is restricted and case mapping support extends to all characters in globalization-invariant mode.
ms.date: 07/23/2021
---
# Culture creation and case mapping in globalization-invariant mode

This breaking change affects *globalization-invariant mode* in two ways:

- Previously, .NET allowed any culture to be created in globalization-invariant mode, as long as the culture name conformed to [BCP-47](https://tools.ietf.org/search/bcp47). However, [the invariant culture](/dotnet/api/system.globalization.cultureinfo?view=net-5.0#invariant-neutral-and-specific-cultures) data was used instead of the real culture data. Starting in .NET 6, an exception is thrown if you create any culture other than the invariant culture in globalization-invariant mode.
- Previously, globalization-invariant mode only supported case mapping for ASCII characters. Starting in .NET 6, globalization-invariant mode provides full case-mapping support for all Unicode-defined characters. Case mapping is used in operations such as string comparisons, string searches, and upper or lower casing strings.

[Globalization-invariant mode](https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md) is used for apps that don't required any globalization support. That is, the app runs without access to culture-specific data and behavior. Globalization-invariant mode is enabled by default on some Docker containers, for example, Alpine containers.

## Old behavior

In previous .NET versions when globalization-invariant mode is enabled:

- If an app creates a culture that's not the invariant culture, the operation succeeds but the returned culture always use the invariant culture data instead of the real culture data.
- Case mapping was performed only for ASCII characters. For example:

```csharp
if ("Á".Equals("á", StringComparison.CurrentCultureIgnoreCase)) // Evaluates to false.
```

## New behavior

Starting in .NET 6 when globalization-invariant mode is enabled:

- If an app attempts to create a culture that's not the invariant culture, a <xref:System.Globalization.CultureNotFoundException> exception is thrown.
- Case mapping is performed for all Unicode-defined characters. For example:

```csharp
if ("Á".Equals("á", StringComparison.CurrentCultureIgnoreCase)) // Evaluates to true.
```

## Version introduced

.NET 6 Preview 7

## Reason for change

The culture-creation change was introduced to more easily diagnose culture-related problems. Some users are unaware that their apps are running in an environment where globalization-invariant mode is enabled. They may experience unexpected behavior and don't make the association with globalization-invariant mode, so it's hard to diagnose the issue.

The full case-mapping support was introduced for better usability and experience in globalization-invariant mode.

## Recommended action

In most cases, no action is needed. However, if you desire the previous culture-creation behavior, you can set a run-time configuration option to allow creation of any culture in globalization-invariant mode. For more information, see [Predefined cultures](../../../run-time-config/globalization.md#predefined-cultures).

## Affected APIs

- <xref:System.Globalization.CultureInfo.%23ctor%2A>
- <xref:System.Globalization.CultureInfo.CreateSpecificCulture(System.String)?displayProperty=fullName>
- <xref:System.Globalization.CultureInfo.GetCultureInfo%2A?displayProperty=fullName>
- <xref:System.Globalization.RegionInfo.%23ctor%2A>
- Any APIs that perform string casing, comparison, or searching

## See also

- [.NET globalization invariant mode](https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md)
- [Invariant, neutral, and specific cultures](/dotnet/api/system.globalization.cultureinfo?view=net-5.0#invariant-neutral-and-specific-cultures)
8 changes: 8 additions & 0 deletions docs/core/compatibility/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ items:
href: core-libraries/6.0/numeric-format-parsing-handles-higher-precision.md
- name: Unhandled exceptions from a BackgroundService
href: core-libraries/6.0/hosting-exception-handling.md
- name: Globalization
items:
- name: Culture creation and case mapping in globalization-invariant mode
href: globalization/6.0/culture-creation-invariant-mode.md
- name: JIT compiler
items:
- name: Call argument coercion
Expand Down Expand Up @@ -639,6 +643,10 @@ items:
href: /ef/core/what-is-new/ef-core-3.x/breaking-changes?toc=/dotnet/core/compatibility/toc.json&bc=/dotnet/breadcrumb/toc.json
- name: Globalization
items:
- name: .NET 6
items:
- name: Culture creation and case mapping in globalization-invariant mode
href: globalization/6.0/culture-creation-invariant-mode.md
- name: .NET 5
items:
- name: Use ICU libraries on Windows
Expand Down
13 changes: 13 additions & 0 deletions docs/core/project-sdk/msbuild-props.md
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,7 @@ You can configure some run-time behaviors by specifying MSBuild properties in th

- [ConcurrentGarbageCollection](#concurrentgarbagecollection)
- [InvariantGlobalization](#invariantglobalization)
- [PredefinedCulturesOnly](#predefinedculturesonly)
- [RetainVMGarbageCollection](#retainvmgarbagecollection)
- [ServerGarbageCollection](#servergarbagecollection)
- [ThreadPoolMaxThreads](#threadpoolmaxthreads)
Expand Down Expand Up @@ -649,6 +650,18 @@ The `InvariantGlobalization` property configures whether the app runs in *global
</PropertyGroup>
```

### PredefinedCulturesOnly

In .NET 6 and later versions, the `PredefinedCulturesOnly` property configures whether apps can create cultures other than the invariant culture when [globalization-invariant mode](https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md) is enabled. The default is `true`. Set the value to `false` to allow creation of any new culture in globalization-invariant mode.

```xml
<PropertyGroup>
<PredefinedCulturesOnly>false</PredefinedCulturesOnly>
</PropertyGroup>
```

For more information, see [Culture creation and case mapping in globalization-invariant mode](../compatibility/globalization/6.0/culture-creation-invariant-mode.md).

### RetainVMGarbageCollection

The `RetainVMGarbageCollection` property configures the garbage collector to put deleted memory segments on a standby list for future use or release them. Setting the value to `true` tells the garbage collector to put the segments on a standby list. For more information, see [Retain VM](../run-time-config/garbage-collector.md#retain-vm).
Expand Down
12 changes: 12 additions & 0 deletions docs/core/run-time-config/globalization.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,15 @@ Project file:
| - | - | - | - |
| **runtimeconfig.json** | `System.Globalization.UseNls` | `false` - Use ICU globalization APIs<br/>`true` - Use NLS globalization APIs | .NET 5.0 |
| **Environment variable** | `DOTNET_SYSTEM_GLOBALIZATION_USENLS` | `false` - Use ICU globalization APIs<br/>`true` - Use NLS globalization APIs | .NET 5.0 |

## Predefined cultures

- Configures whether apps can create cultures other than the invariant culture when [globalization-invariant mode](https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md) is enabled.
- If you omit this setting, .NET restricts the creation of cultures in globalization-invariant mode. This is equivalent to setting the value to `true`.
- For more information, see [Culture creation and case mapping in globalization-invariant mode](../compatibility/globalization/6.0/culture-creation-invariant-mode.md).

| | Setting name | Values | Introduced |
| - | - | - | - |
| **runtimeconfig.json** | `System.Globalization.PredefinedCulturesOnly` | `true` - In globalization-invariant mode, don't allow creation of any culture except the invariant culture.<br/>`false` - Allow creation of any culture. | .NET 6 |
| **MSBuild property** | `PredefinedCulturesOnly` | `true` - In globalization-invariant mode, don't allow creation of any culture except the invariant culture.<br/>`false` - Allow creation of any culture. | .NET 6 |
| **Environment variable** | `DOTNET_SYSTEM_GLOBALIZATION_PREDEFINED_CULTURES_ONLY` | `true` - In globalization-invariant mode, don't allow creation of any culture except the invariant culture.<br/>`false` - Allow creation of any culture. | .NET 6 |
12 changes: 6 additions & 6 deletions docs/core/run-time-config/index.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
---
title: Run-time config options
description: Learn how to configure .NET Core applications by using run-time configuration settings.
ms.date: 01/21/2020
description: Learn how to configure .NET applications by using run-time configuration settings.
ms.date: 07/23/2021
---
# .NET Core run-time configuration settings
# .NET run-time configuration settings

.NET Core supports the use of configuration files and environment variables to configure the behavior of .NET Core applications at run time. Run-time configuration is an attractive option if:
.NET 5+ (including .NET Core versions) supports the use of configuration files and environment variables to configure the behavior of .NET applications at run time. Run-time configuration is an attractive option if:

- You don't own or control the source code for an application and therefore are unable to configure it programmatically.

Expand All @@ -14,7 +14,7 @@ ms.date: 01/21/2020
> [!NOTE]
> This documentation is a work in progress. If you notice that the information presented here is either incomplete or inaccurate, either [open an issue](https://github.com/dotnet/docs/issues) to let us know about it, or [submit a pull request](https://github.com/dotnet/docs/pulls) to address the issue. For information about submitting pull requests for the dotnet/docs repository, see the [contributor's guide](/contribute/dotnet/dotnet-contribute).

.NET Core provides the following mechanisms for configuring application behavior at run time:
.NET provides the following mechanisms for configuring application behavior at run time:

- The [runtimeconfig.json file](#runtimeconfigjson)

Expand All @@ -23,7 +23,7 @@ ms.date: 01/21/2020
- [Environment variables](#environment-variables)

> [!TIP]
> Configuring a run-time option by using an environment variable applies the setting to all .NET Core apps. Configuring a run-time option in the *runtimeconfig.json* or project file applies the setting to that application only.
> Configuring a run-time option by using an environment variable applies the setting to all .NET apps. Configuring a run-time option in the *runtimeconfig.json* or project file applies the setting to that application only.

Some configuration values can also be set programmatically by calling the <xref:System.AppContext.SetSwitch%2A?displayProperty=nameWithType> method.

Expand Down