# CoreFx breaking changes

Important

This article is under construction. This is not a complete list of .NET Core breaking changes. For more information on .NET Core breaking changes, you can examine individual breaking changes issues in the dotnet/docs repository on GitHub.

The following is a list of CoreFx breaking changes by .NET Core version. CoreFx provides the primitives and other general types used by .NET Core.

## .NET Core 3.0 Preview 7

### JsonElement API changes

Starting with .NET Core 3.0 Preview 7, some JsonElement APIs have changed to allow for easier discovery and greater usability.

#### Change description

In .NET Core 3.0 Preview 7, JsonElement APIs have changed as follows to allow for easier discovery and greater usability.

1. All WriteProperty method overloads were removed from JsonElement. This affects code such as the following:

using (JsonDocument doc = JsonDocument.Parse(jsonString))
{
JsonElement root = doc.RootElement;
root.WriteProperty(propertyNameString, writer);
// ..
root.WriteProperty(propertyNameSpan, writer);
// ..
root.WriteProperty(propertyNameJsonEncoded, writer);
// ..
root.WriteProperty(utf8PropertyName, writer);
//..
}

2. WriteValue was renamed as WriteTo. This affects code such as the following:

 using (JsonDocument doc = JsonDocument.Parse(jsonString))
{
JsonElement root = doc.RootElement;
root.WriteValue(writer);
}

3. WriteTo now throws an ArgumentNullException when its method parameter is null.

#### Version introduced

3.0 Preview 7

If your code is affected by these changes, you can do the following:

• There is no replacement API for the WriteProperty overloads in JsonElement. Instead, you can call one of the Utf8JsonWriter.WritePropertyName overloads along with the WriteTo method to achive the same result. For example:

using (JsonDocument doc = JsonDocument.Parse(jsonString))
{
JsonElement root = doc.RootElement;
writer.WritePropertyName(propertyNameString);
root.WriteTo(writer);
}

• Rename the WriteValue method to WriteTo(Utf8JsonWriter). The method parameter remains unchanged. For example, the previous code should be changed to the following:

using (JsonDocument doc = JsonDocument.Parse(jsonString))
{
JsonElement root = doc.RootElement;
root.WriteTo(writer);
}

• Handle the ArgumentNullException in calls to the WriteTo method.

## .NET Core 3.0 Preview 8

### Change in semantics of (string)null in Utf8JsonWriter

In .NET Core 3.0 Preview 7, the null string is treated as the empty string in Utf8JsonWriter. Starting with .NET Core 3.0 Preview 8, the null string throws an exception when used as a property name, and it emits the JSON null token when used as a value.

#### Change description

In .NET Core 3.0 Preview 7, the null string was treated as "" both when writing property names and when writing values.

Starting with .NET Core 3.0 Preview 8, a null property name throws an ArgumentNullException, and a null value is treated as a call to Utf8JsonWriter.WriteNull or Utf8JsonWriter.WriteNullValue().

Consider the following code:

string propertyName1 = null;
string propertyValue1 = null;
string propertyName2 = "prop2";
string propertyValue2 = null;
string simpleValue1 = null;

using (Utf8JsonWriter writer = new Utf8JsonWriter(stream))
{
writer.WriteStartArray();

writer.WriteStartObject();
writer.WriteString(propertyName1, propertyValue1);
writer.WriteString(propertyName2, propertyValue2);
writer.WriteEndObject();

writer.WriteStringValue(simpleValue1);

writer.WriteEndArray();
}


If run with .NET Core 3.0 Preview 7, the writer produces the following output:

[{"":"","prop2":""},""]


Starting with .NET Core 3.0 Preview 8, the call to writer.WriteString(propertyName1, propertyValue1) throws an ArgumentNullException. If propertyName1 = null is replaced with propertyName1 = string.Empty, the output would now be:

[{"":null,"prop2":null},null]


This change was made to better align with caller expectations for null values.

#### Version introduced

3.0 Preview 8

When writing property names and values with the Utf8JsonWriter class:

• Ensure non-null strings are used as property names.

• If the previous behavior is desired, use a null coalescing invocation; for example, writer.WriteString(propertyName1 ?? "", propertyValue1).

• If writing a null literal for a null string value is not desirable, use a null coalescing invocation; for example, writer.WriteString(propertyName2, propertyValue2 ?? "").

CoreFx

### JsonEncodedText.Encode methods have an additional JavaScriptEncoder argument

Starting with .NET Core 3.0 Preview 8, the JsonEncodedText.Encode methods contain an optional JavaScriptEncoder argument.

#### Change description

.NET Core 3.0 includes a new type, xref:System.Text.Json.JsonEncodedText.Encode%2A?displayProperty=nameWithType>. Starting with .NET Core 3.0 Preview 8, the signature of all JsonEncodedText.Encode method overloads has changed to include an optional JavaScriptEncoder parameter. This change was made to allow for a different or custom encoder.

The signature of the Encode methods in .NET Core 3.0 Preview 7 is:

namespace System.Text.Json
{
public readonly struct JsonEncodedText
{
public static JsonEncodedText Encode(ReadOnlySpan<byte> utf8Value);
public static JsonEncodedText Encode(ReadOnlySpan<char> value);
public static JsonEncodedText Encode(string value);
}
}


The signature of the same Encode methods in .NET Core 3.0 Preview 8 and later versions is:

namespace System.Text.Json
{
public readonly struct JsonEncodedText
{
public static JsonEncodedText Encode(ReadOnlySpan<byte> utf8Value, JavaScriptEncoder encoder = null);
public static JsonEncodedText Encode(ReadOnlySpan<char> value, JavaScriptEncoder encoder = null);
public static JsonEncodedText Encode(string value, JavaScriptEncoder encoder = null);
}
}


#### Version introduced

.NET Core 3.0 Preview 8

This is a binary breaking change only; a recompile against .NET Core 3.0 Preview 8 or a later version will fix any runtime issues.

CoreFx

### JsonFactoryConverter.CreateConverter signature changed

To facilitate the composition of JsonConverterFactory classes, the CreateConverter method has been made public and given a second argument of type JsonSerializerOptions.

#### Change description

The signature of the CreateConverter method in .NET Core prior to version 3.0 Preview 8 was:

namespace System.Text.Json.Serialization
{
public abstract class JsonConverterFactory : JsonConverter
{
protected abstract JsonConverter CreateConverter(Type typeToConvert);
}
}


In .NET Core 3.0 Preview 8 and later versions, it is:

namespace System.Text.Json.Serialization
{
public abstract class JsonConverterFactory : JsonConverter
{
public abstract JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options);
}
}


Before this change, it was difficult to compose sealed factory converters, since there was no easy way to get the JsonConverter<T> from it. Making the factory method public and also passing the current JsonSerializerOptions allow for much more flexible composition.

#### Version introduced

3.0 Preview 8

Derived classes need to be updated and recompiled.

## .NET Core 3.0 Preview 9

### Json serializer exception type changed from JsonException to NotSupportedException

In .NET Core 3.0 Preview 6 through 8, the serializer would throw a JsonException when it encountered an unsupported derived collection type. Starting in .NET Core 3.0 Preview 9, the serializer throws a NotSupportedException instead.

#### Change description

In .NET Core 3.0 Preview 6 through Preview 8, the serializer would throw a JsonException when it encountered an unsupported derived collection type. An unsupported derived collection type is any collection type that isn't assignable to one of the following types:

Starting with .NET Core 3.0 Preview 9, the serializer throws a NotSupportedException When encountering an unsupported collection type. The new exception type better reflects why the deserialization operation is failing.

#### Version introduced

3.0 Preview 9

If you're catching JsonException when deserializing, you might want to consider also catching NotSupportedException.

CoreFx

## .NET Core 3.0

### APIs that report version now report product and not file version

Many of the APIs that return versions in .NET Core now returned the product version rather than the file version.

#### Change description

In .NET Core 2.2 and previous versions, methods such as Environment.Version, RuntimeInformation.FrameworkDescription, and the file properties dialog for .NET Core assemblies reflect the file version. Starting with .NET Core 3.0, they reflect the product version.

The following figure illustrates the difference in version information for the System.Runtime.dll assembly for .NET Core 2.2 (on the left) and .NET Core 3.0 (on the right) as displayed by the Windows Explorer file properties dialog.

#### Version introduced

3.0

None. This change should make version detection intuitive rather than obtuse.

CoreFx

### Custom EncoderFallbackBuffer instances cannot fall back recursively

Custom EncoderFallbackBuffer instances cannot fall back recursively. The implementation of EncoderFallbackBuffer.GetNextChar() must result in a character sequence that is convertible to the destination encoding. Otherwise, an exception occurs.

#### Change description

During a character-to-byte transcoding operation, the runtime detects ill-formed or nonconvertible UTF-16 sequences and provides those characters to the EncoderFallbackBuffer.Fallback method. The Fallback method determines which characters should be substituted for the original nonconvertible data, and these characters are drained by calling EncoderFallbackBuffer.GetNextChar in a loop.

The runtime then attempts to transcode these substitution characters to the target encoding. If this operation succeeds, the runtime continues transcoding from where it left off in the original input string.

In .NET Core Preview 7 and earlier versions, custom implementations of EncoderFallbackBuffer.GetNextChar() can return character sequences that are not convertible to the destination encoding. If the substituted characters cannot be transcoded to the target encoding, the runtime invokes the EncoderFallbackBuffer.Fallback method once again with the substitution characters, expecting the EncoderFallbackBuffer.GetNextChar() method to return a new substitution sequence. This process continues until the runtime eventually sees a well-formed, convertible substitution, or until a maximum recursion count is reached.

Starting with .NET Core 3.0, custom implementations of EncoderFallbackBuffer.GetNextChar() must return character sequences that are convertible to the destination encoding. If the substituted characters cannot be transcoded to the target encoding, an ArgumentException is thrown. The runtime will no longer make recursive calls into the EncoderFallbackBuffer instance.

This behavior only applies when all three of the following conditions are met:

• The runtime detects an ill-formed UTF-16 sequence or a UTF-16 sequence that cannot be converted to the target encoding.
• A custom EncoderFallback has been specified.
• The custom EncoderFallback attempts to substitute a new ill-formed or nonconvertible UTF-16 sequence.

#### Version introduced

3.0

Most developers needn't take any action.

If an application uses a custom EncoderFallback and EncoderFallbackBuffer class, ensure the implementation of EncoderFallbackBuffer.Fallback populates the fallback buffer with well-formed UTF-16 data that is directly convertible to the target encoding when the Fallback method is first invoked by the runtime.

CoreFx

### Floating-point formatting and parsing behavior changed

Floating point parsing and formatting behavior (by the Double and Single types) are now IEEE-compliant.

#### Change description

In .NET Core 2.2 and earlier versions, formatting with Double.ToString and Single.ToString, and parsing with Double.Parse, Double.TryParse, Single.Parse, and Single.TryParse are not IEEE-compliant. As a result, it is impossible to guarantee that a value will roundtrip with any supported standard or custom format string. For some inputs, the attempt to parse a formatted value can fail, and for others, the parsed value doesn't equal the original value.

Starting with .NET Core 3.0, parsing and formatting operations are IEEE 754-compliant. This ensures that the behavior of floating-point types in .NET matches that of IEEE-compliant languages such as C#. For more information, see the Floating-point parsing and formatting improvements in .NET Core 3.0 blog post.

#### Version introduced

3.0

The "Potential impact to existing code" section of the Floating-point parsing and formatting improvements in .NET Core 3.0 blog post suggests changes to your code if you observe a change of behavior when compared to .NET Core 2.2 applications Generally, this involves using a different standard or custom format string to enforce the desired behavior. Some results may not have a workaround if they were previously incorrect.

CoreFx

### Floating-point parsing operations no longer fail or throw an OverflowException

The floating-point parsing methods no longer throw an OverflowException or return false when they parse a string whose numeric value is outside the range of the Single or Double floating-point type.

#### Change description

In .NET Core 2.2 and earlier versions, the Double.Parse and Single.Parse methods throw an OverflowException for values that outside the range of their respective type. The Double.TryParse and Single.TryParse methods return false for the string representations of out-of-range numeric values.

Starting with .NET Core 3.0, the Double.Parse, Double.TryParse, Single.Parse, and Single.TryParse methods no longer fail when parsing out-of-range numeric strings. Instead, the Double parsing methods return Double.PositiveInfinity for values that exceed Double.MaxValue, and they return Double.NegativeInfinity for values that are less than Double.MinValue. Similarly, the Single parsing methods return Single.PositiveInfinity for values that exceed Single.MaxValue, and they return Single.NegativeInfinity for values that are less than Single.MinValue.

This change was made for improved IEEE 754:2008 compliance.

#### Version introduced

3.0

This change can affect your code in either of two ways:

• Your code depends on the handler for the OverflowException to execute when an overflow occurs. In this case, you should remove the catch statement and place any necessary code in an If statement that tests whether Double.IsInfinity or Single.IsInfinity is true.

• Your code assumes that floating-point values are not Infinity. In this case, you should add the necessary code to check for floating-point values of PositiveInfinity and NegativeInfinity.

CoreFx

### InvalidAsynchronousStateException moved to another assembly

The InvalidAsynchronousStateException class has been moved.

#### Change description

In .NET Core 2.2 and earlier versions, the InvalidAsynchronousStateException class is found in the System.ComponentModel.TypeConverter assembly.

Starting with .NET Core 3.0, it is found in the System.ComponentModel.Primitives assembly.

#### Version introduced

3.0

This change only affects applications that use reflection to load the InvalidAsynchronousStateException by calling a method such as Assembly.GetType or an overload of Activator.CreateInstance that assumes the type is in a particular assembly. If that is the case, the assembly the assembly referenced in the method call should be updated to reflect the type's new assembly location.

CoreFx

• None

### .NET Core 3.0 follows Unicode best practices when replacing ill-formed UTF-8 byte sequences

When the UTF8Encoding class encounters an ill-formed UTF-8 byte sequence during a byte-to-character transcoding operation, it will replace that sequence with a '�' (U+FFFD REPLACEMENT CHARACTER) character in the output string. .NET Core 3.0 differs from previous versions of .NET Core and the .NET Framework by following the Unicode best practice for performing this replacement during the transcoding operation.

This is part of a larger effort to improve UTF-8 handling throughout .NET, including by the new System.Text.Unicode.Utf8 and System.Text.Rune types. The UTF8Encoding type was given improved error handling mechanics so that it produces output consistent with the newly introduced types.

#### Change description

Starting with .NET Core 3.0, when transcoding bytes to characters, the UTF8Encoding class performs character substitution based on Unicode best practices. The substitution mechanism used is described by The Unicode Standard, Version 12.0, Sec. 3.9 (PDF) in the heading titled U+FFFD Substitution of Maximal Subparts.

This behavior only applies when the input byte sequence contains ill-formed UTF-8 data. Additionally, if the UTF8Encoding instance has been constructed with throwOnInvalidBytes: true (see the [UTF8Encoding constructor documentation](UTF8Encoding(Boolean, Boolean), the UTF8Encoding instance will continue to throw on invalid input rather than perform U+FFFD replacement.

The following illustrates the impact of this change with an invalid 3-byte input:

Ill-formed 3-byte input Output before .NET Core 3.0 Output starting with .NET Core 3.0
[ ED A0 90 ] [ FFFD FFFD ] (2-character output) [ FFFD FFFD FFFD ] (3-character output)

This 3-char output is the preferred output, according to Table 3-9 of the previously linked Unicode Standard PDF.

#### Version introduced

3.0

No action is required on the part of the developer.

CoreFx

### TypeDescriptionProviderAttribute moved to another assembly

The TypeDescriptionProviderAttribute class has been moved.

#### Change description

In .NET Core 2.2 and earlier versions, The TypeDescriptionProviderAttribute class is found in the System.ComponentModel.TypeConverter assembly.

Starting with .NET Core 3.0, it is found in the System.ObjectModel assembly.

#### Version introduced

3.0

This change only affects applications that use reflection to load the TypeDescriptionProviderAttribute type by calling a method such as Assembly.GetType or an overload of Activator.CreateInstance that assumes the type is in a particular assembly. If that is the case, the assembly referenced in the method call should be updated to reflect the type's new assembly location.

Windows Forms

• None

### ZipArchiveEntry no longer handles archives with inconsistent entry sizes

Zip archives list both compressed size and uncompressed size in the central directory and local header. The entry data itself also indicates its size. In .NET Core 2.2 and earlier versions, these values were never checked for consistency. Starting with .NET Core 3.0, they now are.

#### Change description

In .NET Core 2.2 and earlier versions, ZipArchiveEntry.Open() succeeds even if the local header disagrees with the central header of the zip file. Data is decompressed until the end of the compressed stream is reached, even if its length exceeds the uncompressed file size listed in the central directory/local header.

Starting with .NET Core 3.0, the ZipArchiveEntry.Open() method checks that local header and central header agree on compressed and uncompressed sizes of an entry. If they do not, the method throws an InvalidDataException if the archive's local header and/or data descriptor list sizes that disagree with the central directory of the zip file. When reading an entry, decompressed data is truncated to the uncompressed file size listed in the header.

This change was made to ensure that a ZipArchiveEntry correctly represents the size of its data and that only that amount of data is read.

#### Version introduced

3.0

Repackage any zip archive that exhibits these problems.

CoreFx