Retargeting changes for migration to .NET Framework 4.6.x
This article lists the app compatibility issues that were introduced in .NET Framework 4.6, 4.6.1, and 4.6.2.
.NET Framework 4.6
ASP.NET
HtmlTextWriter does not render <br/>
element correctly
Details
Beginning in the .NET Framework 4.6, calling RenderBeginTag(String) and RenderEndTag() with a <BR />
element will correctly insert only one <BR />
(instead of two)
Suggestion
If an app depended on the extra <BR />
tag, RenderBeginTag(String) should be called a second time. Note that this behavior change only affects apps that target the .NET Framework 4.6 or later, so another option is to target a previous version of the .NET Framework in order to get the old behavior.
Name | Value |
---|---|
Scope | Edge |
Version | 4.6 |
Type | Retargeting |
Affected APIs
ClickOnce
Apps published with ClickOnce that use a SHA-256 code-signing certificate may fail on Windows 2003
Details
The executable is signed with SHA256. Previously, it was signed with SHA1 regardless of whether the code-signing certificate was SHA-1 or SHA-256. This applies to:
- All applications built with Visual Studio 2012 or later.
- Applications built with Visual Studio 2010 or earlier on systems with the .NET Framework 4.5 present. In addition, if the .NET Framework 4.5 or later is present, the ClickOnce manifest is also signed with SHA-256 for SHA-256 certificates regardless of the .NET Framework version against which it was compiled.
Suggestion
The change in signing the ClickOnce executable affects only Windows Server 2003 systems; they require that KB 938397 be installed. The change in signing the manifest with SHA-256 even when an app targets the .NET Framework 4.0 or earlier versions introduces a runtime dependency on the .NET Framework 4.5 or a later version.
Name | Value |
---|---|
Scope | Edge |
Version | 4.5 |
Type | Retargeting |
ClickOnce supports SHA-256 on 4.0-targeted apps
Details
Previously, a ClickOnce app with a certificate signed with SHA-256 would require .NET Framework 4.5 or later to be present, even if the app targeted 4.0. Now, .NET Framework 4.0-targeted ClickOnce apps can run on .NET Framework 4.0, even if signed with SHA-256.
Suggestion
This change removes that dependency and allows SHA-256 certificates to be used to sign ClickOnce apps that target .NET Framework 4 and earlier versions.
Name | Value |
---|---|
Scope | Minor |
Version | 4.6 |
Type | Retargeting |
Core
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
- CultureInfo.CurrentCulture
- Thread.CurrentCulture
- CultureInfo.CurrentUICulture
- Thread.CurrentUICulture
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 |
Entity Framework
Building an Entity Framework edmx with Visual Studio 2013 can fail with error MSB4062 if using the EntityDeploySplit or EntityClean tasks
Details
MSBuild 12.0 tools (included in Visual Studio 2013) changed MSBuild file locations, causing older Entity Framework targets files to be invalid. The result is that EntityDeploySplit
and EntityClean
tasks fail because they are unable to find Microsoft.Data.Entity.Build.Tasks.dll
. Note that this break is because of a toolset (MSBuild/VS) change, not because of a .NET Framework change. It will only occur when upgrading developer tools, not when merely upgrading the .NET Framework.
Suggestion
Entity Framework targets files are fixed to work with the new MSBuild layout beginning in the .NET Framework 4.6. Upgrading to that version of the Framework will fix this issue. Alternatively, this workaround can be used to patch the targets files directly.
Name | Value |
---|---|
Scope | Major |
Version | 4.5.1 |
Type | Retargeting |
JIT
IL ret not allowed in a try region
Details
Unlike the JIT64 just-in-time compiler, RyuJIT (used in .NET Framework 4.6) does not allow an IL ret instruction in a try region. Returning from a try region is disallowed by the ECMA-335 specification, and no known managed compiler generates such IL. However, the JIT64 compiler will execute such IL if it is generated using reflection emit.
Suggestion
If an app is generating IL that includes a ret opcode in a try region, the app may target .NET Framework 4.5 to use the old JIT and avoid this break. Alternatively, the generated IL may be updated to return after the try region.
Name | Value |
---|---|
Scope | Edge |
Version | 4.6 |
Type | Retargeting |
New 64-bit JIT compiler in the .NET Framework 4.6
Details
Starting with the .NET Framework 4.6, a new 64-bit JIT compiler is used for just-in-time compilation. In some cases, an unexpected exception is thrown or a different behavior is observed than if an app is run using the 32-bit compiler or the older 64-bit JIT compiler. This change does not affect the 32-bit JIT compiler. The known differences include the following:
- Under certain conditions, an unboxing operation may throw a NullReferenceException in Release builds with optimization turned on.
- In some cases, execution of production code in a large method body may throw a StackOverflowException.
- Under certain conditions, structures passed to a method are treated as reference types rather than as value types in Release builds. One of the manifestations of this issue is that the individual items in a collection appear in an unexpected order.
- Under certain conditions, the comparison of UInt16 values with their high bit set is incorrect if optimization is enabled.
- Under certain conditions, particularly when initializing array values, memory initialization by the OpCodes.Initblk IL instruction may initialize memory with an incorrect value. This can result either in an unhandled exception or incorrect output.
- Under certain rare conditions, a conditional bit test can return the incorrect Boolean value or throw an exception if compiler optimizations are enabled.
- Under certain conditions, if an
if
statement is used to test for a condition before entering atry
block and in the exit from thetry
block, and the same condition is evaluated in thecatch
orfinally
block, the new 64-bit JIT compiler removes theif
condition from thecatch
orfinally
block when it optimizes code. As a result, code inside theif
statement in thecatch
orfinally
block is executed unconditionally.
Suggestion
Mitigation of known issues
If you encounter the issues listed above, you can address them by doing any of the following:
Upgrade to the .NET Framework 4.6.2. The new 64-bit compiler included with the .NET Framework 4.6.2 addresses each of these known issues.
Ensure that your version of Windows is up to date by running Windows Update. Service updates to the .NET Framework 4.6 and 4.6.1 address each of these issues except the NullReferenceException in an unboxing operation.
Compile with the older 64-bit JIT compiler. See the Mitigation of other issues section for more information on how to do this. Mitigation of other issues
If you encounter any other difference in behavior between code compiled with the older 64-bit compiler and the new 64-bit JIT compiler, or between the debug and release versions of your app that are both compiled with the new 64-bit JIT compiler, you can do the following to compile your app with the older 64-bit JIT compiler:On a per-application basis, you can add the < element to your application's configuration file. The following disables compilation with the new 64-bit JIT compiler and instead uses the legacy 64-bit JIT compiler.
<?xml version ="1.0"?> <configuration> <runtime> <useLegacyJit enabled="1" /> </runtime> </configuration>
On a per-user basis, you can add a
REG_DWORD
value nameduseLegacyJit
to theHKEY_CURRENT_USER\SOFTWARE\Microsoft\.NETFramework
key of the registry. A value of 1 enables the legacy 64-bit JIT compiler; a value of 0 disables it and enables the new 64-bit JIT compiler.On a per-machine basis, you can add a
REG_DWORD
value nameduseLegacyJit
to theHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework
key of the registry. A value of1
enables the legacy 64-bit JIT compiler; a value of0
disables it and enables the new 64-bit JIT compiler. You can also let us know about the problem by reporting a bug on Microsoft Connect.
Name | Value |
---|---|
Scope | Edge |
Version | 4.6 |
Type | Retargeting |
Networking
Certificate EKU OID validation
Details
Starting with .NET Framework 4.6, the SslStream or ServicePointManager classes perform enhanced key use (EKU) object identifier (OID) validation. An enhanced key usage (EKU) extension is a collection of object identifiers (OIDs) that indicate the applications that use the key. EKU OID validation uses remote certificate callbacks to ensure that the remote certificate has the correct OIDs for the intended purpose.
Suggestion
If this change is undesirable, you can disable certificate EKU OID validation by adding the following switch to the <AppContextSwitchOverrides> in the ` of your app configuration file:
<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontCheckCertificateEKUs=true" />
</runtime>
Important
This setting is provided for backward compatibility only. Its use is otherwise not recommended.
Name | Value |
---|---|
Scope | Minor |
Version | 4.6 |
Type | Retargeting |
Affected APIs
- System.Net.Security.SslStream
- System.Net.ServicePointManager
- System.Net.Http.HttpClient
- System.Net.Mail.SmtpClient
- System.Net.HttpWebRequest
- System.Net.FtpWebRequest
Only Tls 1.0, 1.1 and 1.2 protocols supported in System.Net.ServicePointManager and System.Net.Security.SslStream
Details
Starting with the .NET Framework 4.6, the ServicePointManager and SslStream classes are only allowed to use one of the following three protocols: Tls1.0, Tls1.1, or Tls1.2. The SSL3.0 protocol and RC4 cipher are not supported.
Suggestion
The recommended mitigation is to upgrade the sever-side app to Tls1.0, Tls1.1, or Tls1.2. If this is not feasible, or if client apps are broken, the System.AppContext class can be used to opt out of this feature in either of two ways:
- By programmatically setting compat switches on the System.AppContext, as explained here.
- By adding the following line to the
<runtime>
section of the app.config file:
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=true"/>
Name | Value |
---|---|
Scope | Minor |
Version | 4.6 |
Type | Retargeting |
Affected APIs
TLS 1.x by default passes the SCH_SEND_AUX_RECORD flag to the underlying SCHANNEL API
Details
When using TLS 1.x, the .NET Framework relies on the underlying Windows SCHANNEL API. Starting with .NET Framework 4.6, the SCH_SEND_AUX_RECORD flag is passed by default to SCHANNEL. This causes SCHANNEL to split data to be encrypted into two separate records, the first as a single byte and the second as n-1 bytes. In rare cases, this breaks communication between clients and existing servers that make the assumption that the data resides in a single record.
Suggestion
If this change breaks communication with an existing server, you can disable sending the SCH_SEND_AUX_RECORD flag and restore the previous behavior of not splitting data into separate records by adding the following switch to the <AppContextSwitchOverrides>
element in the <runtime>
section of your app configuration file:
<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchSendAuxRecord=true" />
</runtime>
Important
This setting is provided for backward compatibility only. Its use is otherwise not recommended.
Name | Value |
---|---|
Scope | Edge |
Version | 4.6 |
Type | Retargeting |
Affected APIs
- System.Net.Security.SslStream
- System.Net.ServicePointManager
- System.Net.Http.HttpClient
- System.Net.Mail.SmtpClient
- System.Net.HttpWebRequest
- System.Net.FtpWebRequest
Windows Communication Foundation (WCF)
Calling CreateDefaultAuthorizationContext with a null argument has changed
Details
The implementation of the System.IdentityModel.Policy.AuthorizationContext returned by a call to the System.IdentityModel.Policy.AuthorizationContext.CreateDefaultAuthorizationContext(IList<IAuthorizationPolicy>) with a null authorizationPolicies argument has changed its implementation in the .NET Framework 4.6.
Suggestion
In rare cases, WCF apps that use custom authentication may see behavioral differences. In such cases, the previous behavior can be restored in either of two ways:
Recompile your app to target an earlier version of the .NET Framework than 4.6. For IIS-hosted services, use the
<httpRuntime targetFramework="x.x">
element to target an earlier version of the .NET Framework.Add the following line to the
<appSettings>
section of your app.config file:<add key="appContext.SetSwitch:Switch.System.IdentityModel.EnableCachedEmptyDefaultAuthorizationContext" value="true" />
Name | Value |
---|---|
Scope | Minor |
Version | 4.6 |
Type | Retargeting |
Affected APIs
Windows Forms
Icon.ToBitmap successfully converts icons with PNG frames into Bitmap objects
Details
Starting with the apps that target the .NET Framework 4.6, the Icon.ToBitmap method successfully converts icons with PNG frames into Bitmap objects.
In apps that target the .NET Framework 4.5.2 and earlier versions, the Icon.ToBitmap method throws an ArgumentOutOfRangeException exception if the Icon object has PNG frames.
This change affects apps that are recompiled to target the .NET Framework 4.6 and that implement special handling for the ArgumentOutOfRangeException that is thrown when an Icon object has PNG frames. When running under the .NET Framework 4.6, the conversion is successful, an ArgumentOutOfRangeException is no longer thrown, and therefore the exception handler is no longer invoked.
Suggestion
If this behavior is undesirable, you can retain the previous behavior by adding the following element to the <runtime>
section of your app.config file:
<AppContextSwitchOverrides
value="Switch.System.Drawing.DontSupportPngFramesInIcons=true" />
If the app.config file already contains the AppContextSwitchOverrides
element, the new value should be merged with the value attribute like this:
<AppContextSwitchOverrides
value="Switch.System.Drawing.DontSupportPngFramesInIcons=true;<previous key>=<previous value>" />
Name | Value |
---|---|
Scope | Minor |
Version | 4.6 |
Type | Retargeting |
Affected APIs
Windows Presentation Foundation (WPF)
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 |
WPF layout rounding of margins has changed
Details
The way in which margins are rounded and borders and the background inside of them has changed. As a result of this change:
- The width or height of elements may grow or shrink by at most one pixel.
- The placement of an object can move by at most one pixel.
- Centered elements can be vertically or horizontally off center by at most one pixel. By default, this new layout is enabled only for apps that target the .NET Framework 4.6.
Suggestion
Since this modification tends to eliminate clipping of the right or bottom of WPF controls at high DPIs, apps that target earlier versions of the .NET Framework but are running on the .NET Framework 4.6 can opt into this new behavior by adding the following line to the <runtime>
section of the app.config file:
<AppContextSwitchOverrides value="Switch.MS.Internal.DoNotApplyLayoutRoundingToMarginsAndBorderThickness=false" />
Apps that target the .NET Framework 4.6 but want WPF controls to render using the previous layout algorithm can do so by adding the following line to the <runtime>
section of the app.config file:
<AppContextSwitchOverrides value="Switch.MS.Internal.DoNotApplyLayoutRoundingToMarginsAndBorderThickness=true" />
Name | Value |
---|---|
Scope | Minor |
Version | 4.6 |
Type | Retargeting |
XML, XSLT
XmlWriter throws on invalid surrogate pairs
Details
For apps that target the .NET Framework 4.5.2 or previous versions, writing an invalid surrogate pair using exception fallback handling does not always throw an exception. For apps that target the .NET Framework 4.6, attempting to write an invalid surrogate pair throws an System.ArgumentException.
Suggestion
If necessary, this break can be avoided by targeting the .NET Framework 4.5.2 or earlier. Alternatively, invalid surrogate pairs can be pre-processed into valid xml prior to writing them.
Name | Value |
---|---|
Scope | Edge |
Version | 4.6 |
Type | Retargeting |
Affected APIs
- XmlWriter.WriteAttributeString(String, String)
- XmlWriter.WriteAttributeString(String, String, String)
- XmlWriter.WriteAttributeString(String, String, String, String)
- XmlWriter.WriteAttributeStringAsync(String, String, String, String)
- XmlWriter.WriteCData(String)
- XmlWriter.WriteCDataAsync(String)
- XmlWriter.WriteChars(Char[], Int32, Int32)
- XmlWriter.WriteCharsAsync(Char[], Int32, Int32)
- XmlWriter.WriteComment(String)
- XmlWriter.WriteCommentAsync(String)
- XmlWriter.WriteEntityRef(String)
- XmlWriter.WriteEntityRefAsync(String)
- XmlWriter.WriteRaw(Char[], Int32, Int32)
- XmlWriter.WriteProcessingInstruction(String, String)
- XmlWriter.WriteProcessingInstructionAsync(String, String)
- XmlWriter.WriteRaw(String)
- XmlWriter.WriteRawAsync(Char[], Int32, Int32)
- XmlWriter.WriteRawAsync(String)
- XmlWriter.WriteString(String)
- XmlWriter.WriteStringAsync(String)
- XmlWriter.WriteSurrogateCharEntity(Char, Char)
- XmlWriter.WriteSurrogateCharEntityAsync(Char, Char)
- XmlWriter.WriteValue(String)
XSD Schema validation now correctly detects violations of unique constraints if compound keys are used and one key is empty
Details
Versions of the .NET Framework prior to 4.6 had a bug that caused XSD validation to not detect unique constraints on compound keys if one of the keys was empty. In the .NET Framework 4.6, this issue is corrected. This will result in more correct validation, but it may also result in some XML not validating which previously would have.
Suggestion
If looser .NET Framework 4.0 validation is needed, the validating application can target version 4.5 (or earlier) of the .NET Framework. When retargeting to .NET Framework 4.6, however, code review should be done to be sure that duplicate compound keys (as described in this issue's description) are not expected to validate.
Name | Value |
---|---|
Scope | Edge |
Version | 4.6 |
Type | Retargeting |
.NET Framework 4.6.1
Core
Change in path separator character in FullName property of ZipArchiveEntry objects
Details
For apps that target the .NET Framework 4.6.1 and later versions, the path separator character has changed from a backslash ("\") to a forward slash ("/") in the FullName property of ZipArchiveEntry objects created by overloads of the CreateFromDirectory method. The change brings the .NET implementation into conformity with section 4.4.17.1 of the .ZIP File Format Specification and allows .ZIP archives to be decompressed on non-Windows systems.
Decompressing a zip file created by an app that targets a previous version of the .NET Framework on non-Windows operating systems such as the Macintosh fails to preserve the directory structure. For example, on the Macintosh, it creates a set of files whose filename concatenates the directory path, along with any backslash ("\") characters, and the filename. As a result, the directory structure of decompressed files is not preserved.
Suggestion
The impact of this change on .ZIP files that are decompressed on the Windows operating system by APIs in the .NET Framework System.IO namespace should be minimal, since these APIs can seamlessly handle either a forward slash ("/") or a backslash ("\") as the path separator character.
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.IO.Compression.ZipFile.UseBackslash
opt-out switch:
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.Compression.ZipFile.UseBackslash=true" />
</runtime>
In addition, apps that target previous versions of the .NET Framework but are running on the .NET Framework 4.6.1 and later versions can opt in to this behavior by adding a configuration setting to the <runtime>
section of the application configuration file. The following shows both the <runtime>
section and the Switch.System.IO.Compression.ZipFile.UseBackslash
opt-in switch.
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.Compression.ZipFile.UseBackslash=false" />
</runtime>
Name | Value |
---|---|
Scope | Edge |
Version | 4.6.1 |
Type | Retargeting |
Affected APIs
- ZipFile.CreateFromDirectory(String, String)
- ZipFile.CreateFromDirectory(String, String, CompressionLevel, Boolean)
- ZipFile.CreateFromDirectory(String, String, CompressionLevel, Boolean, Encoding)
Windows Communication Foundation (WCF)
WCF binding with the TransportWithMessageCredential security mode
Details
Beginning in the .NET Framework 4.6.1, WCF binding that uses the TransportWithMessageCredential security mode can be set up to receive messages with unsigned "to" headers for asymmetric security keys.By default, unsigned "to" headers will continue to be rejected in .NET Framework 4.6.1. They will only be accepted if an application opts into this new mode of operation using the Switch.System.ServiceModel.AllowUnsignedToHeader configuration switch.
Suggestion
Because this is an opt-in feature, it should not affect the behavior of existing apps.
To control whether the new behavior is used or not, use the following configuration setting:
<runtime>
<AppContextSwitchOverrides value="Switch.System.ServiceModel.AllowUnsignedToHeader=true" />
</runtime>
Name | Value |
---|---|
Scope | Transparent |
Version | 4.6.1 |
Type | Retargeting |
Affected APIs
- BasicHttpSecurityMode.TransportWithMessageCredential
- BasicHttpsSecurityMode.TransportWithMessageCredential
- SecurityMode.TransportWithMessageCredential
- WSFederationHttpSecurityMode.TransportWithMessageCredential
X509CertificateClaimSet.FindClaims Considers All claimTypes
Details
In apps that target the .NET Framework 4.6.1, if an X509 claim set is initialized from a certificate that has multiple DNS entries in its SAN field, the System.IdentityModel.Claims.X509CertificateClaimSet.FindClaims(String, String) method attempts to match the claimType argument with all the DNS entries.For apps that target previous versions of the .NET Framework, the System.IdentityModel.Claims.X509CertificateClaimSet.FindClaims(String, String) method attempts to match the claimType argument only with the last DNS entry.
Suggestion
This change only affects applications targeting the .NET Framework 4.6.1. This change may be disabled (or enabled if targeting pre-4.6.1) with the DisableMultipleDNSEntries compatibility switch.
Name | Value |
---|---|
Scope | Minor |
Version | 4.6.1 |
Type | Retargeting |
Affected APIs
Windows Forms
Application.FilterMessage no longer throws for re-entrant implementations of IMessageFilter.PreFilterMessage
Details
Prior to the .NET Framework 4.6.1, calling FilterMessage(Message) with an PreFilterMessage(Message) which called System.Windows.Forms.Application.AddMessageFilter(IMessageFilter) or System.Windows.Forms.Application.RemoveMessageFilter(IMessageFilter) (while also calling DoEvents()) would cause an System.IndexOutOfRangeException.
Beginning with applications targeting .NET Framework 4.6.1, this exception is no longer thrown, and re-entrant filters as described above may be used.
Suggestion
Be aware that FilterMessage(Message) will no longer throw for the re-entrant PreFilterMessage(Message) behavior described above. This only affects applications targeting the .NET Framework 4.6.1.Apps targeting the .NET Framework 4.6.1 can opt out of this change (or apps targeting older Frameworks may opt in) by using the DontSupportReentrantFilterMessage compatibility switch.
Name | Value |
---|---|
Scope | Edge |
Version | 4.6.1 |
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 |
.NET Framework 4.6.2
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
.
Name | Value |
---|---|
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 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
- ClaimsIdentity(IIdentity)
- ClaimsIdentity(IIdentity, IEnumerable<Claim>)
- ClaimsIdentity(IIdentity, IEnumerable<Claim>, String, String, String)
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
- CultureInfo.CurrentCulture
- Thread.CurrentCulture
- CultureInfo.CurrentUICulture
- Thread.CurrentUICulture
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).
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
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 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
- RSA.ImportParameters(RSAParameters)
- RSACng.ImportParameters(RSAParameters)
- RSACertificateExtensions.GetRSAPrivateKey(X509Certificate2)
- RSACertificateExtensions.GetRSAPublicKey(X509Certificate2)
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
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 ConcurrencyMode.Multiple. For example:
[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:
- You retrieve the value of the OperationContext.Current property in a method that returns a Task or Task<TResult>.
- You instantiate the OperationContextScope object in a
using
clause. - You retrieve the value of the OperationContext.Current property within the
using statement
. For example:
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
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)
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 |