Retargeting Changes for Migration from .NET Framework 4.6.1 to 4.6.2

Introduction

Retargeting changes affect apps that are recompiled to target a different .NET Framework. They include:

  • Changes in the design-time environment. For example, build tools may emit warnings when previously they did not.

  • Changes in the runtime environment. These affect only apps that specifically target the retargeted .NET Framework. Apps that target previous versions of the .NET Framework behave as they did when running under those versions.

In the topics that describe etargeting changes, we have classified individual items by their expected impact, as follows:

Major This is a significant change that affects a large number of apps or that requires substantial modification of code.

Minor This is a change that affects a small number of apps or that requires minor modification of code.

Edge case This is a change that affects apps under very specific scenarios that are not common.

Transparent This is a change that has no noticeable effect on the app's developer or user. The app should not require modification because of this change.

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

ASP.NET

HttpRuntime.AppDomainAppPath Throws a NullReferenceException

Details In the .NET Framework 4.6.2, the runtime throws a T:System.NullReferenceException when retrieving a P:System.Web.HttpRuntime.AppDomainAppPath value that includes null characters.In the .NET Framework 4.6.1 and earlier versions, the runtime throws an T:System.ArgumentNullException.
Suggestion You can do either of the follow to respond to this change:
  • Handle the T:System.NullReferenceException if you application is running on the .NET Framework 4.6.2.
  • Upgrade to the .NET Framework 4.7, which restores the previous behavior and throws an T:System.ArgumentNullException.
Scope Edge
Version 4.6.2
Type Retargeting
Affected APIs

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 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 TransformBlock(Byte[], Int32, Int32, Byte[], Int32) after a call to 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>
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 IIdentity parameter set the Actor property. If the IIdentity argument is a ClaimsIdentity object, and the Actor property of that ClaimsIdentity object is not null, the Actor property is attached by using the Clone() method. In the Framework 4.6.1 and earlier versions, the Actor property is attached as an existing reference.Because of this change, starting with the .NET Framework 4.6.2, the Actor property of the new ClaimsIdentity object is not equal to the Actor property of the constructor's 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>
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 \.</code> 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>
Scope Minor
Version 4.6.2
Type Retargeting

CurrentCulture and CurrentUICulture flow across tasks

Details Beginning in the .NET Framework 4.6, CurrentCulture and CurrentUICulture are stored in the thread's ExecutionContext, which flows across asynchronous operations.This means that changes to CurrentCulture or 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 CurrentCulture and CurrentUICulture in all asynchronous tasks).
Suggestion Apps affected by this change may work around it by explicitly setting the desired CurrentCulture or CurrentUICulture as the first operation in an async Task. Alternatively, the old behavior (of not flowing CurrentCulture/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 4.6 or later will automatically get the right behavior in WPF applications - CurrentCulture/CurrentUICulture) would be preserved across Dispatcher operations.
Scope Minor
Version 4.6
Type Retargeting
Affected APIs
Analyzers
  • CD0146

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 PathTooLongException because a path exceeded 260 characters will now throw a 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 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 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 to the <runtime> section of your app.config file:
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.BlockLongPaths=false" />
</runtime>
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 used to be tolerated.
Suggestion If passing a URI to affected APIs, modify the string to be a legal path first.
  • Remove the scheme from URLs manually (e.g. 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.
Scope Edge
Version 4.6.2
Type Retargeting
Affected APIs

Security

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 GetRSAPublicKey(X509Certificate2) and GetRSAPrivateKey(X509Certificate2) extension methods. A 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 CryptographicExceptions.
Suggestion If there is any exception handling logic that relies on the previous behavior where a CryptographicException is thrown when non-standard key sizes are used, consider removing the logic.
Scope Edge
Version 4.6.2
Type Retargeting
Affected APIs
Analyzers
  • CD0148

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:
``
Scope Edge
Version 4.6.2
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:
  • Set the service's concurrency mode to ConcurrencyMode.Single or <System.ServiceModel.ConcurrencyMode.Multiple?displayProperty=nameWithType>. For example:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single)]
  • 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 Rentrant services.
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 context = OperationContext.Current; // OperationContext.Current is null.
// ...
}
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>
Scope Edge
Version 4.6.2
Type Retargeting
Affected APIs

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.ServiceModel.DisableCngCertificates=false" />
</runtime>
This can also be done programmatically with the following code:
private const string DisableCngCertificates = @"Switch.System.ServiceModel.DisableCngCertificate";
AppContext.SetSwitch(disableCngCertificates, false);
Const DisableCngCertificates As String = "Switch.System.ServiceModel.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.
Scope Minor
Version 4.6.2
Type Retargeting

Windows Forms

Incorrect implementation of MemberDescriptor.Equals

Details Original implementation of "Equals" method was comparing two different string properties from the objects under comparison: category name to description string. The fix is to compare "category" of first object to "category" of the second one and "description" to "description". MemberDescriptorEqualsReturnsFalseIfEquivalent configuration value can be set to true to opt out of the new behavior if targeting 4.6.2 or to false to enable this fix when targeting framework version is below 4.6.2.
Suggestion If your application depends on MemberDescriptor.Equals sometimes returning false when descriptors are equivalent, and you are targeting 4.6.2 version of the .NET Framework, you have several options:
  • Make code changes to compare "category" and "description" fields manually in addition to running Equals method.
  • Opt out from this change by adding the following value to the app.config file:
<runtime>
<AppContextSwitchOverrides value="Switch.System.MemberDescriptorEqualsReturnsFalseIfEquivalent=true" />
</runtime>
If your application targets 4.6.1 or lower version of the .NET Framework, 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>
Scope Edge
Version 4.6.2
Type Retargeting
Affected APIs
Analyzers
  • CD0150

Windows Presentation Foundation (WPF)

CurrentCulture is not preserved across WPF Dispatcher operations

Details Beginning in the .NET Framework 4.6, changes to CurrentCulture or CurrentUICulture made within a Dispatcher will be lost at the end of that dispatcher operation. Similarly, changes to CurrentCulture or CurrentUICulture made outside of a Dispatcher operation may not be reflected when that operation executes.Practically speaking, this means that CurrentCulture and CurrentUICulture changes may not flow between WPF UI callbacks and other code in a WPF application.This is due to a change in ExecutionContext that causes CurrentCulture and 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 CurrentCulture and 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 CurrentCulture or CurrentUICulture in a field and checking in all Dispatcher operation bodies (including UI event callback handlers) that the correct CurrentCulture and 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 4.6 or later will automatically get the right behavior in WPF applications - CurrentCulture/CurrentUICulture) would be preserved across Dispatcher operations.
Scope Minor
Version 4.6
Type Retargeting
Analyzers
  • CD0145