Retargeting Changes for Migration from .NET Framework 4.6.1 to 4.7

If you are migrating from the .NET Framework 4.6.1 to 4.7, review the following topics for application compatibility issues that may affect your app:

ASP.NET

Throttle concurrent requests per session

Details

In the .NET Framework 4.6.2 and earlier, ASP.NET executes requests with the same Sessionid sequentially, and ASP.NET always issues the Sessionid through cookies by default. If a page takes a long time to respond, it will significantly degrade server performance just by pressing F5 on the browser. In the fix, we added a counter to track the queued requests and terminate the requests when they exceed a specified limit. The default value is 50. If the limit is reached, a warning will be logged in the event log, and an HTTP 500 response may be recorded in the IIS log.

Suggestion

To restore the old behavior, you can add the following setting to your web.config file to opt out of the new behavior.

<appSettings>
    <add key="aspnet:RequestQueueLimitPerSession" value="2147483647"/>
</appSettings>
Name Value
Scope Edge
Version 4.7
Type Retargeting

Core

AesCryptoServiceProvider decryptor provides a reusable transform

Details

Starting with apps that target the .NET Framework 4.6.2, the AesCryptoServiceProvider decryptor provides a reusable transform. After a call to System.Security.Cryptography.CryptoAPITransform.TransformFinalBlock(Byte[], Int32, Int32), the transform is reinitialized and can be reused. For apps that target earlier versions of the .NET Framework, attempting to reuse the decryptor by calling System.Security.Cryptography.CryptoAPITransform.TransformBlock(Byte[], Int32, Int32, Byte[], Int32) after a call to System.Security.Cryptography.CryptoAPITransform.TransformFinalBlock(Byte[], Int32, Int32) throws a CryptographicException or produces corrupted data.

Suggestion

The impact of this change should be minimal, since this is the expected behavior.Applications that depend on the previous behavior can opt out of it using it by adding the following configuration setting to the <runtime> section of the application's configuration file:

<runtime>
<AppContextSwitchOverrides value="Switch.System.Security.Cryptography.AesCryptoServiceProvider.DontCorrectlyResetDecryptor=true"/>
</runtime>

In addition, applications that target a previous version of the .NET Framework but are running under a version of the .NET Framework starting with .NET Framework 4.6.2 can opt in to it by adding the following configuration setting to the <runtime> section of the application's configuration file:

<runtime>
<AppContextSwitchOverrides value="Switch.System.Security.Cryptography.AesCryptoServiceProvider.DontCorrectlyResetDecryptor=false"/>
</runtime>
Name Value
Scope Minor
Version 4.6.2
Type Retargeting

Affected APIs

Calls to ClaimsIdentity constructors

Details

Starting with the .NET Framework 4.6.2, there is a change in how ClaimsIdentity constructors with an System.Security.Principal.IIdentity parameter set the System.Security.Claims.ClaimsIdentity.Actor property. If the System.Security.Principal.IIdentity argument is a ClaimsIdentity object, and the System.Security.Claims.ClaimsIdentity.Actor property of that ClaimsIdentity object is not null, the System.Security.Claims.ClaimsIdentity.Actor property is attached by using the Clone() method. In the Framework 4.6.1 and earlier versions, the System.Security.Claims.ClaimsIdentity.Actor property is attached as an existing reference.Because of this change, starting with the .NET Framework 4.6.2, the System.Security.Claims.ClaimsIdentity.Actor property of the new ClaimsIdentity object is not equal to the System.Security.Claims.ClaimsIdentity.Actor property of the constructor's System.Security.Principal.IIdentity argument. In the .NET Framework 4.6.1 and earlier versions, it is equal.

Suggestion

If this behavior is undesirable, you can restore the previous behavior by setting the Switch.System.Security.ClaimsIdentity.SetActorAsReferenceWhenCopyingClaimsIdentity switch in your application configuration file to true. This requires that you add the following to the <runtime> section of your web.config file:

<configuration>
  <runtime>
    <AppContextSwitchOverrides value="Switch.System.Security.ClaimsIdentity.SetActorAsReferenceWhenCopyingClaimsIdentity=true" />
  </runtime>
</configuration>
Name Value
Scope Edge
Version 4.6.2
Type Retargeting

Affected APIs

Changes in path normalization

Details

Starting with apps that target the .NET Framework 4.6.2, the way in which the runtime normalizes paths has changed.Normalizing a path involves modifying the string that identifies a path or file so that it conforms to a valid path on the target operating system. Normalization typically involves:

  • Canonicalizing component and directory separators.
  • Applying the current directory to a relative path.
  • Evaluating the relative directory (.) or the parent directory (..) in a path.
  • Trimming specified characters. Starting with apps that target the .NET Framework 4.6.2, the following changes in path normalization are enabled by default:
    • The runtime defers to the operating system's GetFullPathName function to normalize paths.
  • Normalization no longer involves trimming the end of directory segments (such as a space at the end of a directory name).
  • Support for device path syntax in full trust, including \\.\ and, for file I/O APIs in mscorlib.dll, \\?\.
  • The runtime does not validate device syntax paths.
  • The use of device syntax to access alternate data streams is supported. These changes improve performance while allowing methods to access previously inaccessible paths. Apps that target the .NET Framework 4.6.1 and earlier versions but are running under the .NET Framework 4.6.2 or later are unaffected by this change.

Suggestion

Apps that target the .NET Framework 4.6.2 or later can opt out of this change and use legacy normalization by adding the following to the <runtime> section of the application configuration file:

<runtime>
  <AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=true" />
</runtime>

Apps that target the .NET Framework 4.6.1 or earlier but are running on the .NET Framework 4.6.2 or later can enable the changes to path normalization by adding the following line to the <runtime> section of the application .configuration file:

<runtime>
  <AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false" />
</runtime>
Name Value
Scope Minor
Version 4.6.2
Type Retargeting

CurrentCulture and CurrentUICulture flow across tasks

Details

Beginning in the .NET Framework 4.6, System.Globalization.CultureInfo.CurrentCulture and System.Globalization.CultureInfo.CurrentUICulture are stored in the thread's System.Threading.ExecutionContext, which flows across asynchronous operations.This means that changes to System.Globalization.CultureInfo.CurrentCulture or System.Globalization.CultureInfo.CurrentUICulture will be reflected in tasks which are later run asynchronously. This is different from the behavior of previous .NET Framework versions (which would reset System.Globalization.CultureInfo.CurrentCulture and System.Globalization.CultureInfo.CurrentUICulture in all asynchronous tasks).

Suggestion

Apps affected by this change may work around it by explicitly setting the desired System.Globalization.CultureInfo.CurrentCulture or System.Globalization.CultureInfo.CurrentUICulture as the first operation in an async Task. Alternatively, the old behavior (of not flowing System.Globalization.CultureInfo.CurrentCulture/System.Globalization.CultureInfo.CurrentUICulture) may be opted into by setting the following compatibility switch:

AppContext.SetSwitch("Switch.System.Globalization.NoAsyncCurrentCulture", true);

This issue has been fixed by WPF in .NET Framework 4.6.2. It has also been fixed in .NET Frameworks 4.6, 4.6.1 through KB 3139549. Applications targeting .NET Framework 4.6 or later will automatically get the right behavior in WPF applications - System.Globalization.CultureInfo.CurrentCulture/System.Globalization.CultureInfo.CurrentUICulture) would be preserved across Dispatcher operations.

Name Value
Scope Minor
Version 4.6
Type Retargeting

Affected APIs

ETW event names cannot differ only by a "Start" or "Stop" suffix

Details

In the .NET Framework 4.6 and 4.6.1, the runtime throws an ArgumentException when two Event Tracing for Windows (ETW) event names differ only by a "Start" or "Stop" suffix (as when one event is named LogUser and another is named LogUserStart). In this case, the runtime cannot construct the event source, which cannot emit any logging.

Suggestion

To prevent the exception, ensure that no two event names differ only by a "Start" or "Stop" suffix.This requirement is removed starting with the .NET Framework 4.6.2; the runtime can disambiguate event names that differ only by the "Start" and "Stop" suffix.

Name Value
Scope Edge
Version 4.6
Type Retargeting

Long path support

Details

Starting with apps that target the .NET Framework 4.6.2, long paths (of up to 32K characters) are supported, and the 260-character (or MAX_PATH) limitation on path lengths has been removed.For apps that are recompiled to target the .NET Framework 4.6.2, code paths that previously threw a System.IO.PathTooLongException because a path exceeded 260 characters will now throw a System.IO.PathTooLongException only under the following conditions:

  • The length of the path is greater than MaxValue (32,767) characters.
  • The operating system returns COR_E_PATHTOOLONG or its equivalent. For apps that target the .NET Framework 4.6.1 and earlier versions, the runtime automatically throws a System.IO.PathTooLongException whenever a path exceeds 260 characters.

Suggestion

For apps that target the .NET Framework 4.6.2, you can opt out of long path support if it is not desirable by adding the following to the <runtime> section of your app.config file:

<runtime>
  <AppContextSwitchOverrides value="Switch.System.IO.BlockLongPaths=true" />
</runtime>

For apps that target earlier versions of the .NET Framework but run on the .NET Framework 4.6.2 or later, you can opt in to long path support by adding the following to the <runtime> section of your app.config file:

<runtime>
  <AppContextSwitchOverrides value="Switch.System.IO.BlockLongPaths=false" />
</runtime>
Name Value
Scope Minor
Version 4.6.2
Type Retargeting

Path colon checks are stricter

Details

In .NET Framework 4.6.2, a number of changes were made to support previously unsupported paths (both in length and format). Checks for proper drive separator (colon) syntax were made more correct, which had the side effect of blocking some URI paths in a few select Path APIs where they were previously tolerated.

Suggestion

If passing a URI to affected APIs, modify the string to be a legal path first.

  • Remove the scheme from URLs manually (for example, remove file:// from URLs).

  • Pass the URI to the Uri class and use LocalPath.

Alternatively, you can opt out of the new path normalization by setting the Switch.System.IO.UseLegacyPathHandling AppContext switch to true.

Name Value
Scope Edge
Version 4.6.2
Type Retargeting

Affected APIs

Networking

Default value of ServicePointManager.SecurityProtocol is SecurityProtocolType.System.Default

Details

Starting with apps that target the .NET Framework 4.7, the default value of the ServicePointManager.SecurityProtocol property is SecurityProtocolType.SystemDefault. This change allows .NET Framework networking APIs based on SslStream (such as FTP, HTTPS, and SMTP) to inherit the default security protocols from the operating system instead of using hard-coded values defined by the .NET Framework. The default varies by operating system and any custom configuration performed by the system administrator. For information on the default SChannel protocol in each version of the Windows operating system, see Protocols in TLS/SSL (Schannel SSP).

For applications that target an earlier version of the .NET Framework, the default value of the ServicePointManager.SecurityProtocol property depends on the version of the .NET Framework targeted. See the Networking section of Retargeting Changes for Migration from .NET Framework 4.5.2 to 4.6 for more information.

Suggestion

This change affects applications that target the .NET Framework 4.7 or later versions. If you prefer to use a defined protocol rather than relying on the system default, you can explicitly set the value of the ServicePointManager.SecurityProtocol property. If this change is undesirable, you can opt out of it by adding a configuration setting to the <runtime> section of your application configuration file. The following example shows both the <runtime> section and the Switch.System.Net.DontEnableSystemDefaultTlsVersions opt-out switch:

<runtime>
  <AppContextSwitchOverrides value="Switch.System.Net.DontEnableSystemDefaultTlsVersions=true" />
</runtime>
Name Value
Scope Minor
Version 4.7
Type Retargeting

Affected APIs

SslStream supports TLS Alerts

Details

After a failed TLS handshake, an System.IO.IOException with an inner System.ComponentModel.Win32Exception exception will be thrown by the first I/O Read/Write operation. The System.ComponentModel.Win32Exception.NativeErrorCode code for the System.ComponentModel.Win32Exception can be mapped to the TLS Alert from the remote party using the Schannel error codes for TLS and SSL alerts.For more information, see RFC 2246: Section 7.2.2 Error alerts.
The behavior in .NET Framework 4.6.2 and earlier is that the transport channel (usually TCP connection) will timeout during either Write or Read if the other party failed the handshake and immediately afterwards rejected the connection.

Suggestion

Applications calling network I/O APIs such as Read(Byte[], Int32, Int32)/Write(Byte[], Int32, Int32) should handle IOException or System.TimeoutException.
The TLS Alerts feature is enabled by default starting with .NET Framework 4.7. Applications targeting versions of the .NET Framework from 4.0 through 4.6.2 running on a .NET Framework 4.7 or higher system will have the feature disabled to preserve compatibility.
The following configuration API is available to enable or disable the feature for .NET Framework 4.6 and later applications running on .NET Framework 4.7 or later.

  • Programmatically: Must be the very first thing the application does since ServicePointManager will initialize only once:

    AppContext.SetSwitch("TestSwitch.LocalAppContext.DisableCaching", true);
    
    // Set to 'false' to enable the feature in .NET Framework 4.6 - 4.6.2.
    AppContext.SetSwitch("Switch.System.Net.DontEnableTlsAlerts", true);
    
  • AppConfig:

    <runtime>
      <AppContextSwitchOverrides value="Switch.System.Net.DontEnableTlsAlerts=true"/>
      <!-- Set to 'false' to enable the feature in .NET Framework 4.6 - 4.6.2. -->
    </runtime>
    
  • Registry key (machine global): Set the Value to false to enable the feature in .NET Framework 4.6 - 4.6.2.

    Key: HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\AppContext\Switch.System.Net.DontEnableTlsAlerts
    - Type: String
    - Value: "true"
    
Name Value
Scope Edge
Version 4.7
Type Retargeting

Affected APIs

Security

CspParameters.ParentWindowHandle now expects HWND value

Details

The ParentWindowHandle value, introduced in .NET Framework 2.0, allows an application to register a parent window handle value such that any UI required to access the key (such as a PIN prompt or consent dialog) opens as a modal child to the specified window.Starting with apps that target the .NET Framework 4.7, a Windows Forms application can set the ParentWindowHandle property with code like the following:

cspParameters.ParentWindowHandle = form.Handle;

In previous versions of the .NET Framework, the value was expected to be an System.IntPtr representing a location in memory where the HWND value resided. Setting the property to form.Handle on Windows 7 and earlier versions had no effect, but on Windows 8 and later versions, it results in a "System.Security.Cryptography.CryptographicException: The parameter is incorrect."

Suggestion

Applications targeting .NET Framework 4.7 or higher wishing to register a parent window relationship are encouraged to use the simplified form:

cspParameters.ParentWindowHandle = form.Handle;

Users who had identified that the correct value to pass was the address of a memory location which held the value form.Handle can opt out of the behavior change by setting the AppContext switch Switch.System.Security.Cryptography.DoNotAddrOfCspParentWindowHandle to true:

  • By programmatically setting compat switches on the AppContext, as explained here.
  • By adding the following line to the <runtime> section of the app.config file:
<runtime>
 <AppContextSwitchOverrides value="Switch.System.Security.Cryptography.DoNotAddrOfCspParentWindowHandle=true"/>
</runtime>

Conversely, users who wish to opt in to the new behavior on the .NET Framework 4.7 runtime when the application loads under older .NET Framework versions can set the AppContext switch to false.

Name Value
Scope Minor
Version 4.7
Type Retargeting

Affected APIs

RSACng now correctly loads RSA keys of non-standard key size

Details

In .NET Framework versions prior to 4.6.2, customers with non-standard key sizes for RSA certificates are unable to access those keys via the System.Security.Cryptography.X509Certificates.RSACertificateExtensions.GetRSAPublicKey(X509Certificate2) and System.Security.Cryptography.X509Certificates.RSACertificateExtensions.GetRSAPrivateKey(X509Certificate2) extension methods. A System.Security.Cryptography.CryptographicException with the message "The requested key size is not supported" is thrown. In .NET Framework 4.6.2 this issue has been fixed. Similarly, ImportParameters(RSAParameters) and ImportParameters(RSAParameters) now work with non-standard key sizes without throwing a System.Security.Cryptography.CryptographicException.

Suggestion

If there is any exception handling logic that relies on the previous behavior where a System.Security.Cryptography.CryptographicException is thrown when non-standard key sizes are used, consider removing the logic.

Name Value
Scope Edge
Version 4.6.2
Type Retargeting

Affected APIs

SignedXml.GetPublicKey returns RSACng on net462 (or lightup) without retargeting change

Details

Starting with the .NET Framework 4.6.2, the concrete type of the object returned by the SignedXml.GetPublicKey method changed (without a quirk) from a CryptoServiceProvider implementation to a Cng implementation. This is because the implementation changed from using certificate.PublicKey.Key to using the internal certificate.GetAnyPublicKey which forwards to RSACertificateExtensions.GetRSAPublicKey.

Suggestion

Starting with apps running on the .NET Framework 4.7.1, you can use the CryptoServiceProvider implementation used by default in the .NET Framework 4.6.1 and earlier versions by adding the following configuration switch to the runtime section of your app config file:

<AppContextSwitchOverrides value="Switch.System.Security.Cryptography.Xml.SignedXmlUseLegacyCertificatePrivateKey=true" />
Name Value
Scope Edge
Version 4.6.2
Type Retargeting

Affected APIs

SslStream supports TLS Alerts

Details

After a failed TLS handshake, an System.IO.IOException with an inner System.ComponentModel.Win32Exception exception will be thrown by the first I/O Read/Write operation. The System.ComponentModel.Win32Exception.NativeErrorCode code for the System.ComponentModel.Win32Exception can be mapped to the TLS Alert from the remote party using the Schannel error codes for TLS and SSL alerts.For more information, see RFC 2246: Section 7.2.2 Error alerts.
The behavior in .NET Framework 4.6.2 and earlier is that the transport channel (usually TCP connection) will timeout during either Write or Read if the other party failed the handshake and immediately afterwards rejected the connection.

Suggestion

Applications calling network I/O APIs such as Read(Byte[], Int32, Int32)/Write(Byte[], Int32, Int32) should handle IOException or System.TimeoutException.
The TLS Alerts feature is enabled by default starting with .NET Framework 4.7. Applications targeting versions of the .NET Framework from 4.0 through 4.6.2 running on a .NET Framework 4.7 or higher system will have the feature disabled to preserve compatibility.
The following configuration API is available to enable or disable the feature for .NET Framework 4.6 and later applications running on .NET Framework 4.7 or later.

  • Programmatically: Must be the very first thing the application does since ServicePointManager will initialize only once:

    AppContext.SetSwitch("TestSwitch.LocalAppContext.DisableCaching", true);
    
    // Set to 'false' to enable the feature in .NET Framework 4.6 - 4.6.2.
    AppContext.SetSwitch("Switch.System.Net.DontEnableTlsAlerts", true);
    
  • AppConfig:

    <runtime>
      <AppContextSwitchOverrides value="Switch.System.Net.DontEnableTlsAlerts=true"/>
      <!-- Set to 'false' to enable the feature in .NET Framework 4.6 - 4.6.2. -->
    </runtime>
    
  • Registry key (machine global): Set the Value to false to enable the feature in .NET Framework 4.6 - 4.6.2.

    Key: HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\AppContext\Switch.System.Net.DontEnableTlsAlerts
    - Type: String
    - Value: "true"
    
Name Value
Scope Edge
Version 4.7
Type Retargeting

Affected APIs

Windows Communication Foundation (WCF)

Deadlock may result when using Reentrant services

Details

A deadlock may result in a Reentrant service, which restricts instances of the service to one thread of execution at a time. Services prone to encounter this problem will have the following ServiceBehaviorAttribute in their code:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]

Suggestion

To address this issue, you can do the following:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
  • Install the latest update to the .NET Framework 4.6.2, or upgrade to a later version of the .NET Framework. This disables the flow of the ExecutionContext in OperationContext.Current. This behavior is configurable; it is equivalent to adding the following app setting to your configuration file:
<appSettings>
  <add key="Switch.System.ServiceModel.DisableOperationContextAsyncFlow" value="true" />
</appSettings>

The value of Switch.System.ServiceModel.DisableOperationContextAsyncFlow should never be set to false for Reentrant services.

Name Value
Scope Minor
Version 4.6.2
Type Retargeting

Affected APIs

OperationContext.Current may return null when called in a using clause

Details

OperationContext.Current may return null and a NullReferenceException may result if all of the following conditions are true:

using (new OperationContextScope(OperationContext.Current))
{
    // OperationContext.Current is null.
    OperationContext context = OperationContext.Current;

    // ...
}

Suggestion

To address this issue, you can do the following:

  • Modify your code as follows to instantiate a new non- null Current object:

    OperationContext ocx = OperationContext.Current;
    using (new OperationContextScope(OperationContext.Current))
    {
        OperationContext.Current = new OperationContext(ocx.Channel);
    
        // ...
    }
    
  • Install the latest update to the .NET Framework 4.6.2, or upgrade to a later version of the .NET Framework. This disables the flow of the ExecutionContext in OperationContext.Current and restores the behavior of WCF applications in the .NET Framework 4.6.1 and earlier versions. This behavior is configurable; it is equivalent to adding the following app setting to your configuration file:

    <appSettings>
      <add key="Switch.System.ServiceModel.DisableOperationContextAsyncFlow" value="true" />
    </appSettings>
    

    If this change is undesirable and your application depends on execution context flowing between operation contexts, you can enable its flow as follows:

    <appSettings>
      <add key="Switch.System.ServiceModel.DisableOperationContextAsyncFlow" value="false" />
    </appSettings>
    
Name Value
Scope Edge
Version 4.6.2
Type Retargeting

Affected APIs

Serialization of control characters with DataContractJsonSerializer is now compatible with ECMAScript V6 and V8

Details

In .NET Framework 4.6.2 and earlier versions, the System.Runtime.Serialization.Json.DataContractJsonSerializer did not serialize some special control characters, such as \b, \f, and \t, in a way that was compatible with the ECMAScript V6 and V8 standards. Starting with .NET Framework 4.7, serialization of these control characters is compatible with ECMAScript V6 and V8.

Suggestion

For apps that target the .NET Framework 4.7, this feature is enabled by default. If this behavior is not desirable, you can opt out of this feature by adding the following line to the <runtime> section of the app.config or web.config file:

<runtime>
  <AppContextSwitchOverrides value="Switch.System.Runtime.Serialization.DoNotUseECMAScriptV6EscapeControlCharacter=false" />
</runtime>
Name Value
Scope Edge
Version 4.7
Type Retargeting

Affected APIs

WCF message security now is able to use TLS1.1 and TLS1.2

Details

Starting in the .NET Framework 4.7, customers can configure either TLS1.1 or TLS1.2 in WCF message security in addition to SSL3.0 and TLS1.0 through application configuration settings.

Suggestion

In the .NET Framework 4.7, support for TLS1.1 and TLS1.2 in WCF message security is disabled by default. You can enable it by adding the following line to the <runtime> section of the app.config or web.config file:

<runtime>
<AppContextSwitchOverrides value="Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols=false;Switch.System.Net.DontEnableSchUseStrongCrypto=false" />
</runtime>
Name Value
Scope Edge
Version 4.7
Type Retargeting

WCF transport security supports certificates stored using CNG

Details

Starting with apps that target the .NET Framework 4.6.2, WCF transport security supports certificates stored using the Windows Cryptography Library (CNG). This support is limited to certificates with a public key that has an exponent no more than 32 bits in length. When an application targets the .NET Framework 4.6.2, this feature is on by default.In earlier versions of the .NET Framework, the attempt to use X509 certificates with a CSG key storage provider throws an exception.

Suggestion

Apps that target the .NET Framework 4.6.1 and earlier but are running on the .NET Framework 4.6.2 can enable support for CNG certificates by adding the following line to the <runtime> section of the app.config or web.config file:

<runtime>
  <AppContextSwitchOverrides value="Switch.System.IdentityModel.DisableCngCertificates=false" />
</runtime>

This can also be done programmatically with the following code:

private const string DisableCngCertificates = @"Switch.System.IdentityModel.DisableCngCertificate";

AppContext.SetSwitch(disableCngCertificates, false);
Const DisableCngCertificates As String = "Switch.System.IdentityModel.DisableCngCertificates"
AppContext.SetSwitch(disableCngCertificates, False)

Note that, because of this change, any exception handling code that depends on the attempt to initiate secure communication with a CNG certificate to fail will no longer execute.

Name Value
Scope Minor
Version 4.6.2
Type Retargeting

Windows Forms

Incorrect implementation of MemberDescriptor.Equals

Details

The original implementation of the MemberDescriptor.Equals method compares two different string properties from the objects being compared: the category name and the description string. The fix is to compare the Category of the first object to the Category of the second one, and the Description of the first to the Description of the second.

Suggestion

If your application depends on MemberDescriptor.Equals sometimes returning false when descriptors are equivalent, and you are targeting the .NET Framework 4.6.2 or later, you have several options:

  • Make code changes to compare the Category and Description fields manually in addition to calling the MemberDescriptor.Equals method.
  • Opt out of this change by adding the following value to the app.config file:
<runtime>
  <AppContextSwitchOverrides value="Switch.System.MemberDescriptorEqualsReturnsFalseIfEquivalent=true" />
</runtime>

If your application targets .NET Framework 4.6.1 or earlier and is running on the .NET Framework 4.6.2 or later and you want this change enabled, you can set the compatibility switch to false by adding the following value to the app.config file:

<runtime>
  <AppContextSwitchOverrides value="Switch.System.MemberDescriptorEqualsReturnsFalseIfEquivalent=false" />
</runtime>
Name Value
Scope Edge
Version 4.6.2
Type Retargeting

Affected APIs

Windows Presentation Foundation (WPF)

Calls to System.Windows.Input.PenContext.Disable on touch-enabled systems may throw an ArgumentException

Details

Under some circumstances, calls to the internal System.Windows.Intput.PenContext.Disable method on touch-enabled systems may throw an unhandled T:System.ArgumentException because of reentrancy.

Suggestion

This issue has been addressed in the .NET Framework 4.7. To prevent the exception, upgrade to a version of the .NET Framework starting with the .NET Framework 4.7.

Name Value
Scope Edge
Version 4.6.1
Type Retargeting

CurrentCulture is not preserved across WPF Dispatcher operations

Details

Beginning in the .NET Framework 4.6, changes to System.Globalization.CultureInfo.CurrentCulture or System.Globalization.CultureInfo.CurrentUICulture made within a System.Windows.Threading.Dispatcher will be lost at the end of that dispatcher operation. Similarly, changes to System.Globalization.CultureInfo.CurrentCulture or System.Globalization.CultureInfo.CurrentUICulture made outside of a Dispatcher operation may not be reflected when that operation executes.Practically speaking, this means that System.Globalization.CultureInfo.CurrentCulture and System.Globalization.CultureInfo.CurrentUICulture changes may not flow between WPF UI callbacks and other code in a WPF application.This is due to a change in System.Threading.ExecutionContext that causes System.Globalization.CultureInfo.CurrentCulture and System.Globalization.CultureInfo.CurrentUICulture to be stored in the execution context beginning with apps targeting the .NET Framework 4.6. WPF dispatcher operations store the execution context used to begin the operation and restore the previous context when the operation is completed. Because System.Globalization.CultureInfo.CurrentCulture and System.Globalization.CultureInfo.CurrentUICulture are now part of that context, changes to them within a dispatcher operation are not persisted outside of the operation.

Suggestion

Apps affected by this change may work around it by storing the desired System.Globalization.CultureInfo.CurrentCulture or System.Globalization.CultureInfo.CurrentUICulture in a field and checking in all Dispatcher operation bodies (including UI event callback handlers) that the correct System.Globalization.CultureInfo.CurrentCulture and System.Globalization.CultureInfo.CurrentUICulture are set. Alternatively, because the ExecutionContext change underlying this WPF change only affects apps targeting the .NET Framework 4.6 or newer, this break can be avoided by targeting the .NET Framework 4.5.2.Apps that target .NET Framework 4.6 or later can also work around this by setting the following compatibility switch:

AppContext.SetSwitch("Switch.System.Globalization.NoAsyncCurrentCulture", true);

This issue has been fixed by WPF in .NET Framework 4.6.2. It has also been fixed in .NET Frameworks 4.6, 4.6.1 through KB 3139549. Applications targeting .NET Framework 4.6 or later will automatically get the right behavior in WPF applications - System.Globalization.CultureInfo.CurrentCulture/System.Globalization.CultureInfo.CurrentUICulture) would be preserved across Dispatcher operations.

Name Value
Scope Minor
Version 4.6
Type Retargeting

NullReferenceException in exception handling code from ImageSourceConverter.ConvertFrom

Details

An error in the exception handling code for ConvertFrom(ITypeDescriptorContext, CultureInfo, Object) caused an incorrect System.NullReferenceException to be thrown instead of the intended exception ( System.IO.DirectoryNotFoundException or System.IO.FileNotFoundException). This change corrects that error so that the method now throws the right exception.

By default all applications targeting .NET Framework 4.6.2 and earlier continue to throw System.NullReferenceException for compatibility. Developers targeting .NET Framework 4.7 and above should see the right exceptions.

Suggestion

Developers who wish to revert to getting System.NullReferenceException when targeting .NET Framework 4.7 or later can add/merge the following to their application's App.config file:

<configuration>
<runtime>
<AppContextSwitchOverrides value="Switch.System.Windows.Media.ImageSourceConverter.OverrideExceptionWithNullReferenceException=true"/>
</runtime>
</configuration>
Name Value
Scope Edge
Version 4.7
Type Retargeting

Affected APIs

WPF Grid allocation of space to star-columns

Details

Starting with the .NET Framework 4.7, WPF replaces the algorithm that Grid uses to allocate space to *-columns. This will change the actual width assigned to *-columns in a number of cases:

  • When one or more *-columns also have a minimum or maximum width that overrides the proportional allocation for that colum. (The minimum width can derive from an explicit MinWidth declaration, or from an implicit minimum obtained from the column's content. The maximum width can only be defined explicitly, from a MaxWidth declaration.)

  • When one or more *-columns declare an extremely large *-weight, greater than 10^298.

  • When the *-weights are sufficiently different to encounter floating-point instability (overflow, underflow, loss of precision).

  • When layout rounding is enabled, and the effective display DPI is sufficiently high. In the first two cases, the widths produced by the new algorithm can be significantly different from those produced by the old algorithm; in the last case, the difference will be at most one or two pixels.

    The new algorithm fixes several bugs present in the old algorithm:

  • Total allocation to columns can exceed the Grid's width. This can occur when allocating space to a column whose proportional share is less than its minimum size. The algorithm allocates the minimum size, which decreases the space available to other columns. If there are no *-columns left to allocate, the total allocation will be too large.

  • Total allocation can fall short of the Grid's width. This is the dual problem to #1, arising when allocating to a column whose proportional share is greater than its maximum size, with no *-columns left to take up the slack.

  • Two *-columns can receive allocations not proportional to their *-weights. This is a milder version of #1/#2, arising when allocating to *-columns A, B, and C (in that order), where B's proportional share violates its min (or max) constraint. As above, this changes the space available to column C, who gets less (or more) proportional allocation than A did,

  • Columns with extremely large weights (> 10^298) are all treated as if they had weight 10^298. Proportional differences between them (and between columns with slightly smaller weights) are not honored.

  • Columns with infinite weights are not handled correctly. [Actually you can't set a weight to Infinity, but this is an artificial restriction. The allocation code was trying to handle it, but doing a bad job.]

  • Several minor problems while avoiding overflow, underflow, loss of precision and similar floating-point issues.

  • Adjustments for layout rounding are incorrect at sufficiently high DPI. The new algorithm produces results that meet the following criteria:

    A. The actual width assigned to a *-column is never less than its minimum width nor greater than its maximum width.
    B. Each -column that is not assigned its minimum or maximum width is assigned a width proportional to its -weight. To be precise, if two columns are declared with width x and y respectively, and if neither column receives its minimum or maximum width, the actual widths v and w assigned to the columns are in the same proportion: v / w == x / y.
    C. The total width allocated to "proportional" *-columns is equal to the space available after allocating to the constrained columns (fixed, auto, and *-columns that are allocated their min or max width). This might be zero, for instance if the sum of the minimum widths exceeds the Grid's available width.
    D. All these statements are to be interpreted with respect to the "ideal" layout. When layout rounding is in effect, the actual widths can differ from the ideal widths by as much as one pixel.
    The old algorithm honored (A) but failed to honor the other criteria in the cases outlined above.

    Everything said about columns and widths in this article applies as well to rows and heights.

Suggestion

By default, apps that target versions of the .NET Framework starting with the .NET Framework 4.7 will see the new algorithm, while apps that target the .NET Framework 4.6.2 or earlier versions will see the old algorithm.

To override the default, use the following configuration setting:

<runtime>
<AppContextSwitchOverrides value="Switch.System.Windows.Controls.Grid.StarDefinitionsCanExceedAvailableSpace=true" />
</runtime>

The value true selects the old algorithm, false selects the new algorithm.

Name Value
Scope Minor
Version 4.7
Type Retargeting

WPF Pointer-Based Touch Stack

Details

This change adds the ability to enable an optional WM_POINTER based WPF touch/stylus stack. Developers that do not explicitly enable this should see no change in WPF touch/stylus behavior.Current Known Issues With optional WM_POINTER based touch/stylus stack:

  • No support for real-time inking.
  • While inking and StylusPlugins will still work, they will be processed on the UI Thread which can lead to poor performance.
  • Behavioral changes due to changes in promotion from touch/stylus events to mouse events
  • Manipulation may behave differently
  • Drag/Drop will not show appropriate feedback for touch input
  • This does not affect stylus input
  • Drag/Drop can no longer be initiated on touch/stylus events
  • This can potentially cause the application to stop responding until mouse input is detected.
  • Instead, developers should initiate drag and drop from mouse events.

Suggestion

Developers who wish to enable this stack can add/merge the following to their application's App.config file:

<configuration>
<runtime>
<AppContextSwitchOverrides value="Switch.System.Windows.Input.Stylus.EnablePointerSupport=true"/>
</runtime>
</configuration>

Removing this or setting the value to false will turn this optional stack off.Note that this stack is available only on Windows 10 Creators Update and above.

Name Value
Scope Edge
Version 4.7
Type Retargeting

Windows Workflow Foundation (WF)

Workflow checksums changed from MD5 to SHA1

Details

To support debugging with Visual Studio, the Workflow runtime generates a checksum for a workflow instance using a hashing algorithm. In the .NET Framework 4.6.2 and earlier versions, workflow checksum hashing used the MD5 algorithm, which caused issues on FIPS-enabled systems. Starting with the .NET Framework 4.7, the algorithm is SHA1. If your code has persisted these checksums, they will be incompatible.

Suggestion

If your code is unable to load workflow instances due to a checksum failure, try setting the AppContext switch "Switch.System.Activities.UseMD5ForWFDebugger" to true.In code:

System.AppContext.SetSwitch("Switch.System.Activities.UseMD5ForWFDebugger", true);

Or in configuration:

<configuration>
  <runtime>
    <AppContextSwitchOverrides value="Switch.System.Activities.UseMD5ForWFDebugger=true" />
  </runtime>
</configuration>
Name Value
Scope Minor
Version 4.7
Type Retargeting