有关迁移到 .NET Framework 4.6.x 的操作的重定向目标更改
本文列出了 .NET Framework 4.6、4.6.1 和 4.6.2 中引入的应用兼容性问题。
.NET Framework 4.6
ASP.NET
HtmlTextWriter 未正确呈现 <br/>
元素
详细信息
从 .NET Framework 4.6 开始,调用带有 <BR />
的 RenderBeginTag(String) 和 RenderEndTag() 将正确插入唯一 <BR />
(而非两个)
建议
如果应用依赖于多余的 <BR />
标记,应再次调用 RenderBeginTag(String)。 请注意,此行为更改仅影响面向 .NET Framework 4.6 或更高版本的应用,因此另一选项是面向以前版本的 .NET Framework 以便获取旧行为。
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6 |
类型 | 重定目标 |
受影响的 API
ClickOnce
通过 ClickOnce 使用 SHA-256 代码签名证书发布的应用在 Windows 2003 中可能会失败
详细信息
使用 SHA256 对可执行文件签名。 以前,无论代码签名证书是 SHA-1 还是 SHA-256,都使用 SHA1 进行签名。 这适用于:
- 使用 Visual Studio 2012 或更高版本生成的所有应用程序。
- 使用 Visual Studio 2010 或更早版本在安装了 .NET Framework 4.5 的系统上生成的应用程序。 此外,如果安装了 .NET Framework 4.5 或更高版本,则 ClickOnce 清单也会采用 SHA-256 签名,因为 SHA-256 证书与编译所采用的 .NET Framework 版本无关。
建议
更改 ClickOnce 可执行文件的签名仅影响 Windows Server 2003 系统;它们需要安装 KB 938397。 即使应用是面向 .NET Framework 4.0 或早期版本,对使用 SHA-256 签名的清单进行更改,将引入依赖 .NET Framework 4.5 或更高版本的运行时。
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.5 |
类型 | 重定目标 |
ClickOnce 支持面向 4.0 的应用上的 SHA-256
详细信息
以前,如果 ClickOnce 应用具有使用 SHA-256 签名的证书,即使应用面向 4.0 版本,也需要 .NET Framework 4.5 或更高版本。 现在,即使使用 SHA-256 签名,面向 .NET Framework 4.0 的 ClickOnce 应用也可在 .NET Framework 4.0 上运行。
建议
此更改删除了该依赖项,允许将 SHA-256 证书用于为面向 .NET Framework 4 或更早版本的 ClickOnce 应用签名。
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6 |
类型 | 重定目标 |
核心
CurrentCulture 和 CurrentUICulture 在任务之间流动
详细信息
从 .NET Framework 4.6 开始,System.Globalization.CultureInfo.CurrentCulture 和 System.Globalization.CultureInfo.CurrentUICulture 存储在线程的 System.Threading.ExecutionContext 中,可跨异步操作流动。这意味着对 System.Globalization.CultureInfo.CurrentCulture 或 System.Globalization.CultureInfo.CurrentUICulture 的更改将反映在稍后以异步方式运行的任务中。 这与旧版 .NET Framework 的行为不同(旧版会在所有异步任务中重置 System.Globalization.CultureInfo.CurrentCulture 和 System.Globalization.CultureInfo.CurrentUICulture)。
建议
受此更改影响的应用可通过将所需的 System.Globalization.CultureInfo.CurrentCulture 或 System.Globalization.CultureInfo.CurrentUICulture 显式设置为异步任务中的首个操作来暂时解决此问题。 或者,可通过设置以下兼容性开关选择使用旧行为(不流动 System.Globalization.CultureInfo.CurrentCulture/System.Globalization.CultureInfo.CurrentUICulture):
AppContext.SetSwitch("Switch.System.Globalization.NoAsyncCurrentCulture", true);
.NET Framework 4.6.2 中的 WPF 已修复此问题。 .NET Frameworks 4.6、4.6.1 中也通过 KB 3139549 修复了此问题。 面向 .NET Framework 4.6 或更高版本的应用程序将自动在 WPF 应用程序中获取正确行为 - System.Globalization.CultureInfo.CurrentCulture/System.Globalization.CultureInfo.CurrentUICulture 将在调度程序操作中保留。
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6 |
类型 | 重定目标 |
受影响的 API
- CultureInfo.CurrentCulture
- Thread.CurrentCulture
- CultureInfo.CurrentUICulture
- Thread.CurrentUICulture
ETW 事件名称无法仅通过“Start”或“Stop”后缀区别开来
详细信息
在 .NET Framework 4.6 和 4.6.1 中,当两个 Windows 事件跟踪 (ETW) 事件名称只有“Start”或“Stop”后缀不同时(例如,当一个事件命名为 LogUser
,另一个事件命名为 LogUserStart
),运行时会引发 ArgumentException。 在这种情况下,运行时不会构建不能发出任何日志记录的事件源。
建议
若要避免此异常,请确保两个事件名称不是只有“Start”或“Stop”后缀不同。从 .NET Framework 4.6.2 开始,将删除此要求,运行时可区分只有“Start”和“Stop”后缀不同的事件名称。
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6 |
类型 | 重定目标 |
Entity Framework
如果使用 EntityDeploySplit 或 EntityClean 任务,使用 Visual Studio 2013 生成 Entity Framework edmx 会失败,错误编码为 MSB4062
详细信息
MSBuild 12.0 工具(包括在 Visual Studio 2013 中)更改了 MSBuild 文件位置,使得旧 Entity Framework 目标文件变为无效文件。 结果是 EntityDeploySplit
和 EntityClean
任务失败,因为它们无法找到 Microsoft.Data.Entity.Build.Tasks.dll
。 请注意,此中断是由于工具集 (MSBuild/VS) 更改而引起的,并不是因为 .NET Framework 更改。 它仅在升级开发人员工具时才会发生,仅升级 .NET Framework 不会发生。
建议
从 .NET Framework 4.6 开始,Entity Framework 目标文件已修复,可与新 MSBuild 布局一起使用。 升级到该版本的 Framework 将解决此问题。 或者,可使用此解决方法直接修补目标文件。
“属性” | 值 |
---|---|
范围 | 主要 |
Version | 4.5.1 |
类型 | 重定目标 |
JIT
试用区域中不允许 IL ret
详细信息
与 JIT64 实时编译器不同,RyuJIT(在 .NET Framework 4.6 中使用)不允许在试用区域中使用 IL ret 指令。 ECMA-335 规范不允许从试用区域返回,并且没有已知的托管编译器会生成此类 IL。 但是,如果由反射发出生成,则 JIT64 编译器执行此类 IL。
建议
如果应用正在生成在试用区域中包含 ret 操作码的 IL,则该应用会面向 .NET Framework 4.5,使用旧的 JIT 并避免此中断。 或者,生成的 IL 可更新为在试用区域之后返回。
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6 |
类型 | 重定目标 |
.NET Framework 4.6 中新的 64 位 JIT 编译器
详细信息
从 .NET Framework 4.6 开始,新的 64 位 JIT 编译器用于实时编译。 在某些情况下,比起使用 32 位编译器或较旧的 64 位 JIT 编译器运行应用,此举措会引发意外异常或发生其他行为。 此更改不影响 32 位 JIT 编译器。 已知差异如下:
- 在某些情况下,在启用优化的发布版本中,取消装箱操作可能会引发 NullReferenceException。
- 在某些情况下,在大型方法主体中执行生产代码可能会引发 StackOverflowException。
- 在某些情况下,传递给方法的结构将视为引用类型,而不是发布版本中的值类型。 此问题的表现形式之一是,集合中各个项的显示顺序出现异常。
- 在某些情况下,如果启用了优化,无法正确比较 UInt16 值与其高位集。
- 在某些情况下,尤其是在初始化数组值时,通过 OpCodes.Initblk IL 指令执行的内存初始化可能会使用不正确的值初始化内存。 这可能会导致未经处理的异常抛出或输出不正确。
- 在某些极少数情况下,如果启用了编译器优化,条件位测试可能会返回错误的 Boolean 值或引发异常。
- 在某些情况下,如果
if
语句用于在进入try
块之前和从try
块中退出之前测试条件,且在catch
或finally
块中计算的条件相同,那么新版 64 位实时编译器会在优化代码时从catch
或finally
块中删除if
条件。 因此,catch
或finally
块中的if
语句代码会无条件地执行。
建议
已知问题的缓解措施
如果遇到上面列出的问题,可以通过执行下列任一操作来解决:
升级到 .NET Framework 4.6.2。 .NET Framework 4.6.2 随附的新版 64 位编译器解决了上面列出的所有已知问题。
运行 Windows 更新,以确保 Windows 是最新版本。 .NET Framework 4.6 和 4.6.1 服务更新可解决以上问题,取消装箱操作中的 NullReferenceException 除外。
使用旧版 64 位 JIT 编译器进行编译。 请参阅其他问题的缓解措施部分,详细了解如何执行此操作。 其他问题的缓解措施
如果遇到的是旧版和新版 64 位 JIT 编译器编译的代码的其他任何行为差异,或是使用新版 64 位 JIT 编译器编译的应用程序的调试和发布版本的其他任何行为差异,可以使用旧版 64 位 JIT 编译器编译应用程序,具体操作如下:对于每个应用程序,可将 < 元素添加到应用程序配置文件中。 下面的代码禁用新版 64 位 JIT 编译器,改用旧版 64 位 JIT 编译器进行编译。
<?xml version ="1.0"?> <configuration> <runtime> <useLegacyJit enabled="1" /> </runtime> </configuration>
对于每个用户,可以将名为
useLegacyJit
的REG_DWORD
值添加到注册表的HKEY_CURRENT_USER\SOFTWARE\Microsoft\.NETFramework
密钥中。 如果值为 1,可以启用旧版 64 位 JIT 编译器;如果值为 0,可以禁用旧版编译器,启用新版 64 位 JIT 编译器。对于每台计算机,可以将名为
useLegacyJit
的REG_DWORD
值添加到注册表的HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework
密钥中。 如果值为1
,可以启用旧版 64 位 JIT 编译器;如果值为0
,可以禁用旧版编译器,启用新版 64 位 JIT 编译器。 还可以在 Microsoft Connect 上报告 bug,告诉我们你遇到的问题。
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6 |
类型 | 重定目标 |
网络
证书 EKU OID 验证
详细信息
从 .NET Framework 4.6 开始,SslStream 或 ServicePointManager 类执行增强型密钥使用 (EKU) 对象标识符 (OID) 验证。 增强型密钥使用 (EKU) 扩展是指示使用密钥的应用程序的对象标识符 (OID) 的集合。 EKU OID 验证使用远程证书回叫来确保远程证书具有用于预期目的的正确 OID。
建议
如果无需此更改,则可通过将以下开关添加到应用配置文件中 ` 的 <AppContextSwitchOverrides> 来禁用证书 EKU OID 验证:
<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontCheckCertificateEKUs=true" />
</runtime>
重要
此设置仅用于后向兼容性。 否则不建议使用它。
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6 |
类型 | 重定目标 |
受影响的 API
- System.Net.Security.SslStream
- System.Net.ServicePointManager
- System.Net.Http.HttpClient
- System.Net.Mail.SmtpClient
- System.Net.HttpWebRequest
- System.Net.FtpWebRequest
System.Net.ServicePointManager 和 System.Net.Security.SslStream 中仅支持 Tls 1.0、1.1 和 1.2 协议
详细信息
从 .NET Framework 4.6 开始,ServicePointManager 和 SslStream 类仅可使用以下三种协议之一:Tls1.0、Tls1.1 或 Tls1.2。 不支持 SSL3.0 协议和 RC4 密码。
建议
建议的缓解操作是将服务器端应用升级到 Tls1.0、Tls1.1 或 Tls1.2。 如果这不可行或者如果客户端应用被中断,则可以使用 System.AppContext 类并采用如两种方式中的一种来选择退出此功能:
- 以编程方式在 System.AppContext 上设置兼容性开关,如此处所述。
- 在 app.config 文件的
<runtime>
部分中添加下面的代码行:
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=true"/>
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6 |
类型 | 重定目标 |
受影响的 API
默认情况下,TLS 1.x 将 SCH_SEND_AUX_RECORD 标记传递给基础 SCHANNEL API
详细信息
使用 TLS 1.x 时,.NET Framework 依赖于基础 Windows SCHANNEL API。 从 .NET Framework 4.6 开始,SCH_SEND_AUX_RECORD 标记默认传递给 SCHANNEL。 这会导致 SCHANNEL 将要加密的数据拆分为两个单独的记录,第一个为单字节,第二个为 n-1 个字节。 在极少数情况下,这会中断客户端与假定数据驻留在单个记录中的现有服务器之间的通信。
建议
如果此更改中断了与现有服务器的通信,则可以将以下开关添加到应用配置文件的 <runtime>
部分中的 <AppContextSwitchOverrides>
元素,禁止发送 SCH_SEND_AUX_RECORD 标记并还原之前不将数据拆分为单独记录的行为:
<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchSendAuxRecord=true" />
</runtime>
重要
此设置仅用于后向兼容性。 否则不建议使用它。
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6 |
类型 | 重定目标 |
受影响的 API
- 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)
调用具有 null 自变量的 CreateDefaultAuthorizationContext 的方式已更改
详细信息
调用具有 null authorizationPolicies 自变量的 System.IdentityModel.Policy.AuthorizationContext.CreateDefaultAuthorizationContext(IList<IAuthorizationPolicy>) 所返回的 System.IdentityModel.Policy.AuthorizationContext 实现更改了其在 .NET Framework 4.6 中的实现。
建议
在极少数情况下,使用自定义身份验证的 WCF 应用可能会看到行为差异。 在这类情况下,可使用以下两种方式之一还原以前的行为:
重新编译你的应用以面向早于 4.6 的 .NET Framework 版本。 对于 IIS 承载的服务,请使用
<httpRuntime targetFramework="x.x">
元素以面向早期版本的 .NET Framework。将下面的行添加到 app.config 文件的
<appSettings>
部分:<add key="appContext.SetSwitch:Switch.System.IdentityModel.EnableCachedEmptyDefaultAuthorizationContext" value="true" />
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6 |
类型 | 重定目标 |
受影响的 API
Windows 窗体
Icon.ToBitmap 成功将带 PNG 帧的图标转换为位图对象
详细信息
从面向 .NET Framework 4.6 的应用开始,Icon.ToBitmap 方法成功将带 PNG 帧的图标转换为 Bitmap 对象。
在面向 .NET Framework 4.5.2 和更低版本的应用中,如果 Icon 对象具有 PNG 帧,Icon.ToBitmap 方法将引发 ArgumentOutOfRangeException 异常。
此更改会影响以下应用:重新编译为面向 .NET Framework 4.6 的应用,以及对在 Icon 对象具有 PNG 帧时引发的 ArgumentOutOfRangeException 实施特殊处理的应用。 在.NET Framework 4.6 下运行时,转换成功,不再引发 ArgumentOutOfRangeException ,因此不再调用异常处理程序。
建议
如果不需要此行为,可以在 app.config 文件的 <runtime>
部分中添加下面的元素,从而保留旧行为:
<AppContextSwitchOverrides
value="Switch.System.Drawing.DontSupportPngFramesInIcons=true" />
如果 app.config 文件中已包含 AppContextSwitchOverrides
元素,则新值应与值特性合并,如下所示:
<AppContextSwitchOverrides
value="Switch.System.Drawing.DontSupportPngFramesInIcons=true;<previous key>=<previous value>" />
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6 |
类型 | 重定目标 |
受影响的 API
Windows Presentation Foundation (WPF)
在 WPF 调度程序操作上不保留 CurrentCulture
详细信息
从 .NET Framework 4.6 开始,在 System.Windows.Threading.Dispatcher 中对 System.Globalization.CultureInfo.CurrentCulture 或 System.Globalization.CultureInfo.CurrentUICulture 的更改将会在该调度程序操作结束时丢失。 同样,在调度程序操作外对 System.Globalization.CultureInfo.CurrentCulture 或 System.Globalization.CultureInfo.CurrentUICulture 的更改在执行该操作时可能不会反映出来。实际上,这意味着 System.Globalization.CultureInfo.CurrentCulture 和 System.Globalization.CultureInfo.CurrentUICulture 更改可能不会在 WPF UI 回调和 WPF 应用程序中的其他代码之间流动。这是因为,从面向 .NET Framework 4.6 的应用开始,System.Threading.ExecutionContext 中的一项更改使 System.Globalization.CultureInfo.CurrentCulture 和 System.Globalization.CultureInfo.CurrentUICulture 存储在执行上下文中。 WPF 调度程序操作存储用于启动操作的执行上下文,并在操作完成时还原以前的上下文。 由于 System.Globalization.CultureInfo.CurrentCulture 和 System.Globalization.CultureInfo.CurrentUICulture 现在属于该上下文,因此,在调度程序操作中对它们所做的更改在操作之外不会保留。
建议
受此更改影响的应用可在字段中存储所需的 System.Globalization.CultureInfo.CurrentCulture 或 System.Globalization.CultureInfo.CurrentUICulture,并在所有调度程序操作正文(包括 UI 事件回调处理程序)中检查是否设置了正确的 System.Globalization.CultureInfo.CurrentCulture 和 System.Globalization.CultureInfo.CurrentUICulture。 或者,因为在此 WPF 更改之下的 ExecutionContext 更改仅影响面向 .NET Framework 4.6 或更高版本的应用,面向 .NET Framework 4.5.2 可避免出现此中断。面向 .NET Framework 4.6 或更高版本的应用也可以通过设置以下兼容性开关解决此问题:
AppContext.SetSwitch("Switch.System.Globalization.NoAsyncCurrentCulture", true);
.NET Framework 4.6.2 中的 WPF 已修复此问题。 .NET Frameworks 4.6、4.6.1 中也通过 KB 3139549 修复了此问题。 面向 .NET Framework 4.6 或更高版本的应用程序将自动在 WPF 应用程序中获取正确行为 - System.Globalization.CultureInfo.CurrentCulture/System.Globalization.CultureInfo.CurrentUICulture 将在调度程序操作中保留。
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6 |
类型 | 重定目标 |
边距的 WPF 布局舍入已更改
详细信息
边距舍入的方式以及边框和边框内的背景已更改。 此更改的结果是:
- 元素的宽度或高度最多可以扩大或收缩一个像素。
- 对象的位置最多可以移动一个像素。
- 居中的元素最多可以垂直或水平地偏离中心一个像素。 默认情况下,仅对面向 .NET Framework 4.6 的应用启用此新布局。
建议
由于这种修改往往会消除高 DPI 处 WPF 控件的右侧或底部剪辑,因此面向早期版本的 .NET framework 但在.NET Framework 4.6 上运行的应用可以通过将下面的行添加到 app.config 文件的 <runtime>
部分来选择加入此新行为:
<AppContextSwitchOverrides value="Switch.MS.Internal.DoNotApplyLayoutRoundingToMarginsAndBorderThickness=false" />
面向 .NET Framework 4.6 但希望 WPF 控件使用之前的布局算法来呈现的应用可以通过将下面的行添加到 app.config 文件的 <runtime>
部分来执行此操作:
<AppContextSwitchOverrides value="Switch.MS.Internal.DoNotApplyLayoutRoundingToMarginsAndBorderThickness=true" />
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6 |
类型 | 重定目标 |
XML、XSLT
XmlWriter 引发无效的代理项对
详细信息
对于面向 .NET Framework 4.5.2 或以前的版本的应用程序,使用异常回退处理编写无效的代理项对并不会总是引发异常。 对于面向 .NET Framework 4.6 的应用,尝试编写无效的代理项对会引发 System.ArgumentException。
建议
如有必要,可通过面向 .NET Framework 4.5.2 或更早版本来避免此中断。 或者,可在编写无效的代理项对前将其预处理为有效的 XML。
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6 |
类型 | 重定目标 |
受影响的 API
- 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 架构验证现在可正确检测是否违反唯一约束
详细信息
在版本 4.6 之前的 .NET Framework 版本中存在一个 bug,即如果其中一个密钥为空,XSD 验证无法检测复合密钥上的唯一约束。 在 .NET Framework 4.6 中,此问题已得到更正。 这将导致更多的正确验证,但也可能导致无法像以前版本那样验证某些 XML。
建议
如果需要更宽松的 .NET Framework 4.0 验证,该验证应用程序可以面向版本 4.5(或更早版本)的 .NET Framework。 但在重定向到 .NET Framework 4.6 时,应执行代码评审,确保无需验证重复的复合密钥(如在此问题的描述中所述)。
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6 |
类型 | 重定目标 |
.NET Framework 4.6.1
核心
ZipArchiveEntry 对象的 FullName 属性中的路径分隔符更改
详细信息
对于面向 .NET Framework 4.6.1 及更高版本的应用,在通过重载 CreateFromDirectory 方法创建的 ZipArchiveEntry 对象的 FullName 属性中,路径分隔符已从反斜杠(“\”)改为了正斜杠(“/”)。 该更改使 .NET 实现遵循 .ZIP 文件格式规范的 4.4.17.1 部分,还允许 .ZIP 存档在非 Windows 系统上进行解压缩。
对于面向非 Windows 操作系统(如 Macintosh)上旧版 .NET Framework 的应用程序,解压缩其创建的 zip 文件将无法保留目录结构。 例如,在 Macintosh 上,该应用会创建一组文件,它们的文件名与目录路径相连,还与任何反斜杠(“\”)字符和文件名相连。 因此,不会保留解压缩的文件的目录结构。
建议
此更改对由 .NET Framework System.IO 命名空间中的 API 在 Windows 操作系统上解压缩的 .ZIP 文件的影响应该很小,因为这些 API 可以无缝处理作为路径分隔符的正斜杠(“/”)或反斜杠(“\”)。
如果不需要此更改,可在应用程序配置文件的 <runtime>
部分中添加配置设置,从而选择弃用此更改。 以下示例显示 <runtime>
部分和 Switch.System.IO.Compression.ZipFile.UseBackslash
选择弃用开关:
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.Compression.ZipFile.UseBackslash=true" />
</runtime>
此外,对于面向先前版本的 .NET Framework,但在 .NET Framework 4.6.1 及更高版本上运行的应用,可通过将配置设置添加到应用程序配置文件的 <runtime>
部分来选择启用此行为。 以下展示了 <runtime>
部分和 Switch.System.IO.Compression.ZipFile.UseBackslash
选择弃用开关。
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.Compression.ZipFile.UseBackslash=false" />
</runtime>
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6.1 |
类型 | 重定目标 |
受影响的 API
- ZipFile.CreateFromDirectory(String, String)
- ZipFile.CreateFromDirectory(String, String, CompressionLevel, Boolean)
- ZipFile.CreateFromDirectory(String, String, CompressionLevel, Boolean, Encoding)
Windows Communication Foundation (WCF)
与 TransportWithMessageCredential 安全模式绑定的 WCF
详细信息
从 .NET Framework 4.6.1 开始,可将使用 TransportWithMessageCredential 安全模式的 WCF 绑定设置为接收带有非对称安全密钥的未签名“to”标头的消息。默认情况下,.NET Framework 4.6.1 中将继续拒绝未签名“to”标头。 仅当应用程序使用 Switch.System.ServiceModel.AllowUnsignedToHeader 配置开关选择启用此新操作模式时,才会接受它们。
建议
由于这是一项可以选择使用的功能,因此它不应影响现有应用的行为。
要控制是否使用新行为,请使用以下配置设置:
<runtime>
<AppContextSwitchOverrides value="Switch.System.ServiceModel.AllowUnsignedToHeader=true" />
</runtime>
“属性” | 值 |
---|---|
范围 | 透明 |
Version | 4.6.1 |
类型 | 重定目标 |
受影响的 API
- BasicHttpSecurityMode.TransportWithMessageCredential
- BasicHttpsSecurityMode.TransportWithMessageCredential
- SecurityMode.TransportWithMessageCredential
- WSFederationHttpSecurityMode.TransportWithMessageCredential
X509CertificateClaimSet.FindClaims 考虑到所有 claimTypes
详细信息
在面向 .NET Framework 4.6.1 的应用中,如果从 SAN 字段拥有多个 DNS 条目的证书初始化 X509 声明集,System.IdentityModel.Claims.X509CertificateClaimSet.FindClaims(String, String) 方法会尝试将 claimType 自变量与所有 DNS 条目进行匹配。对于面向以前版本的 .NET Framework 的应用,System.IdentityModel.Claims.X509CertificateClaimSet.FindClaims(String, String) 方法会尝试仅将 claimType 自变量与最后一个 DNS 条目进行匹配。
建议
此更改仅影响面向 .NET Framework 4.6.1 的应用程序。 在 DisableMultipleDNSEntries 兼容性开关中,可能会禁用此更改(如果面向 4.6.1 之前的版本,将启用此更改)。
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6.1 |
类型 | 重定目标 |
受影响的 API
Windows 窗体
IMessageFilter.PreFilterMessage 的可重入实现不会再引发 Application.FilterMessage
详细信息
在 .NET Framework 4.6.1 之前的版本中,使用调用 System.Windows.Forms.Application.AddMessageFilter(IMessageFilter) 或 System.Windows.Forms.Application.RemoveMessageFilter(IMessageFilter)(同时也调用 DoEvents())的 PreFilterMessage(Message) 调用 FilterMessage(Message) 可能导致 System.IndexOutOfRangeException。
从面向 .NET Framework 4.6.1 的应用程序开始,不再引发此异常,并且可能使用上述的可重入筛选器。
建议
请注意,上述的可重入 PreFilterMessage(Message) 行为将不再引发 FilterMessage(Message)。 此更改仅影响面向 .NET Framework 4.6.1 的应用程序。面向 .NET Framework 4.6.1 的应用可使用 DontSupportReentrantFilterMessage 兼容性开关,选择退出此更改(或者面向较早的 Framework 的应用可选择使用此更改)。
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6.1 |
类型 | 重定目标 |
受影响的 API
Windows Presentation Foundation (WPF)
在启用触摸的系统上调用 System.Windows.Input.PenContext.Disable 可能会引发 ArgumentException
详细信息
在某些情况下,在启用触摸的系统上调用内部 System.Windows.Intput.PenContext.Disable 方法可能会因为重新进入而引发未处理的 T:System.ArgumentException
。
建议
此问题已在 .NET Framework 4.7 中得到解决。 若要避免此异常,升级到 .NET Framework 4.7 及以上版本。
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6.1 |
类型 | 重定目标 |
.NET Framework 4.6.2
ASP.NET
HttpRuntime.AppDomainAppPath 引发 NullReferenceException
详细信息
在 .NET Framework 4.6.2 中,当检索包含空字符的 P:System.Web.HttpRuntime.AppDomainAppPath
值时,运行时会引发 T:System.NullReferenceException
。在 .NET Framework 4.6.1 及早期版本中,运行时将引发 T:System.ArgumentNullException
。
建议
可执行以下任一操作来应对此更改:
- 如果应用程序是在 .NET Framework 4.6.2 上运行,请处理
T:System.NullReferenceException
。 - 升级到 .NET Framework 4.7,这将还原以前的行为并引发
T:System.ArgumentNullException
。
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6.2 |
类型 | 重定目标 |
受影响的 API
核心
AesCryptoServiceProvider 解密器提供了可重用的转换
详细信息
从面向 .NET Framework 4.6.2 的应用起,AesCryptoServiceProvider 解密器提供了可重用的转换。 调用 System.Security.Cryptography.CryptoAPITransform.TransformFinalBlock(Byte[], Int32, Int32) 后,此转换将重新初始化并且可以重用。 对于面向旧版 .NET Framework 的应用,在调用 System.Security.Cryptography.CryptoAPITransform.TransformFinalBlock(Byte[], Int32, Int32) 后尝试通过调用 System.Security.Cryptography.CryptoAPITransform.TransformBlock(Byte[], Int32, Int32, Byte[], Int32) 重用解密器会引发 CryptographicException 或导致数据损坏。
建议
此更改的影响应该很小,因为这是预期的行为。对于依赖旧行为的应用程序,可通过将以下配置设置添加到应用程序配置文件的 <runtime>
部分中,从而选择不用此更改:
<runtime>
<AppContextSwitchOverrides value="Switch.System.Security.Cryptography.AesCryptoServiceProvider.DontCorrectlyResetDecryptor=true"/>
</runtime>
此外,对于面向旧版 .NET framework,但在 .NET Framework 4.6.2 及更高版本下运行的应用程序,可通过将以下配置设置添加到应用程序配置文件的 <runtime>
部分,从而选择应用此更改:
<runtime>
<AppContextSwitchOverrides value="Switch.System.Security.Cryptography.AesCryptoServiceProvider.DontCorrectlyResetDecryptor=false"/>
</runtime>
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6.2 |
类型 | 重定目标 |
受影响的 API
调用 ClaimsIdentity 构造函数
详细信息
从 .NET Framework 4.6.2 开始,具有 System.Security.Principal.IIdentity 参数的 ClaimsIdentity 构造函数设置 System.Security.Claims.ClaimsIdentity.Actor 属性的方式发生了变化。 如果 System.Security.Principal.IIdentity 参数是 ClaimsIdentity 对象,且该 ClaimsIdentity 对象的 System.Security.Claims.ClaimsIdentity.Actor 属性不为 null
,则 System.Security.Claims.ClaimsIdentity.Actor 属性是使用 Clone() 方法附加的。 在 Framework 4.6.1 及早期版本中,System.Security.Claims.ClaimsIdentity.Actor 属性作为现有引用进行附加。由于此更改,从 .NET Framework 4.6.2 开始,新 ClaimsIdentity 对象的 System.Security.Claims.ClaimsIdentity.Actor 属性不等于构造函数的 System.Security.Principal.IIdentity 参数的 System.Security.Claims.ClaimsIdentity.Actor 属性。 在 .NET Framework 4.6.1 及更早版本中,它们是相等的。
建议
如果不需要此行为,可以在应用程序配置文件中将 Switch.System.Security.ClaimsIdentity.SetActorAsReferenceWhenCopyingClaimsIdentity
开关设置为 true
,从而还原旧行为。 为此,必须在 web.config 文件的 <runtime>
部分中添加以下内容:
<configuration>
<runtime>
<AppContextSwitchOverrides value="Switch.System.Security.ClaimsIdentity.SetActorAsReferenceWhenCopyingClaimsIdentity=true" />
</runtime>
</configuration>
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6.2 |
类型 | 重定目标 |
受影响的 API
- ClaimsIdentity(IIdentity)
- ClaimsIdentity(IIdentity, IEnumerable<Claim>)
- ClaimsIdentity(IIdentity, IEnumerable<Claim>, String, String, String)
路径规范化中的更改
详细信息
从面向 .NET Framework 4.6.2 的应用开始,运行时规范路径的方式发生了变化。路径规范化涉及修改用于标识路径或文件的字符串,使其与目标操作系统上的有效路径一致。 路径规范化通常涉及以下操作:
- 规范化处理组件和目录分隔符。
- 将当前目录应用到相对路径。
- 评估路径中的相对目录 (.) 或父目录 (..)。
- 删减指定字符。
从面向 .NET Framework 4.6.2 的应用开始,在路径规范化中默认启用以下更改:
- 运行时在规范化处理路径时以操作系统的 GetFullPathName 函数为准。
- 路径规范化再也不用删减目录部分的末尾内容(如目录名称末尾的空格)。
- 支持完全信任形式的设备路径语法,包括
\\.\
和\\?\
(对于 mscorlib.dll 中的文件 I/O API)。 - 运行时不会验证设备语法路径。
- 支持使用设备语法来访问备用数据流。 这些更改会提升性能,同时允许方法访问之前无法访问的路径。 定目标到 .NET Framework 4.6.1 及更低版本、但在 .NET Framework 4.6.2 或更高版本控制下运行的应用不受此更改影响。
建议
对于面向 .NET Framework 4.6.2 或更高版本的应用,可通过将以下内容添加到应用程序配置文件的 <runtime>
部分,选择弃用此更改而使用旧版规范化:
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=true" />
</runtime>
对于面向 .NET Framework 4.6.1 及更低版本,但在 .NET Framework 4.6.2 或更高版本上运行的应用,可通过将以下行添加到应用程序配置文件的 <runtime>
部分,启用对路径规范化的更改:
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false" />
</runtime>
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6.2 |
类型 | 重定目标 |
CurrentCulture 和 CurrentUICulture 在任务之间流动
详细信息
从 .NET Framework 4.6 开始,System.Globalization.CultureInfo.CurrentCulture 和 System.Globalization.CultureInfo.CurrentUICulture 存储在线程的 System.Threading.ExecutionContext 中,可跨异步操作流动。这意味着对 System.Globalization.CultureInfo.CurrentCulture 或 System.Globalization.CultureInfo.CurrentUICulture 的更改将反映在稍后以异步方式运行的任务中。 这与旧版 .NET Framework 的行为不同(旧版会在所有异步任务中重置 System.Globalization.CultureInfo.CurrentCulture 和 System.Globalization.CultureInfo.CurrentUICulture)。
建议
受此更改影响的应用可通过将所需的 System.Globalization.CultureInfo.CurrentCulture 或 System.Globalization.CultureInfo.CurrentUICulture 显式设置为异步任务中的首个操作来暂时解决此问题。 或者,可通过设置以下兼容性开关选择使用旧行为(不流动 System.Globalization.CultureInfo.CurrentCulture/System.Globalization.CultureInfo.CurrentUICulture):
AppContext.SetSwitch("Switch.System.Globalization.NoAsyncCurrentCulture", true);
.NET Framework 4.6.2 中的 WPF 已修复此问题。 .NET Frameworks 4.6、4.6.1 中也通过 KB 3139549 修复了此问题。 面向 .NET Framework 4.6 或更高版本的应用程序将自动在 WPF 应用程序中获取正确行为 - System.Globalization.CultureInfo.CurrentCulture/System.Globalization.CultureInfo.CurrentUICulture 将在调度程序操作中保留。
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6 |
类型 | 重定目标 |
受影响的 API
- CultureInfo.CurrentCulture
- Thread.CurrentCulture
- CultureInfo.CurrentUICulture
- Thread.CurrentUICulture
ETW 事件名称无法仅通过“Start”或“Stop”后缀区别开来
详细信息
在 .NET Framework 4.6 和 4.6.1 中,当两个 Windows 事件跟踪 (ETW) 事件名称只有“Start”或“Stop”后缀不同时(例如,当一个事件命名为 LogUser
,另一个事件命名为 LogUserStart
),运行时会引发 ArgumentException。 在这种情况下,运行时不会构建不能发出任何日志记录的事件源。
建议
若要避免此异常,请确保两个事件名称不是只有“Start”或“Stop”后缀不同。从 .NET Framework 4.6.2 开始,将删除此要求,运行时可区分只有“Start”和“Stop”后缀不同的事件名称。
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6 |
类型 | 重定目标 |
长路径支持
详细信息
从面向 .NET Framework 4.6.2 的应用开始,支持长路径(最多 32K 个字符),并删除了 260 个字符(或 MAX_PATH
)的路径长度限制。对于经过重新编译以面向 .NET Framework 4.6.2 的应用,之前因路径超过 260 个字符而引发 System.IO.PathTooLongException 的代码路径,现在仅在以下情况下引发 System.IO.PathTooLongException:
- 路径长度必须大于 MaxValue (32,767) 个字符。
- 操作系统返回
COR_E_PATHTOOLONG
或其等同项。 对于面向 .NET Framework 4.6.1 及更早版本的应用,只要路径超过 260 个字符,运行时就会自动引发 System.IO.PathTooLongException。
建议
对于面向 .NET Framework 4.6.2 的应用,如果无需长路径支持,可通过将以下内容添加到 app.config
文件的 <runtime>
部分来选择弃用该支持:
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.BlockLongPaths=true" />
</runtime>
对于面向旧版 .NET Framework,但在 .NET Framework 4.6.2 或更高版本上运行的应用,可通过将以下内容添加到 app.config
文件的 <runtime>
部分来选择启用长路径支持:
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.BlockLongPaths=false" />
</runtime>
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6.2 |
类型 | 重定目标 |
路径冒号检查更严格
详细信息
在 .NET Framework 4.6.2 中,为了支持以前不受支持的路径,进行了大量更改(无论是在长度方面还是在格式方面)。 检查正确的驱动器分隔符(冒号)语法变得更加严格,这样做的副作用是阻止了少量特选路径 API 中的某些 URI 路径,而这些之前已被容忍的。
建议
如果将 URI 传递给受影响的 API,请首先将该字符串修改为合法路径。
或者,通过将 Switch.System.IO.UseLegacyPathHandling
AppContext 开关设置为 true
来选择不用新路径规范化。
名称 | 值 |
---|---|
范围 | 边缘 |
Version | 4.6.2 |
类型 | 重定目标 |
受影响的 API
安全性
RSACng 现在可正确加载非标准密钥大小的 RSA 密钥
详细信息
在 .NET Framework 4.6.2 之前的版本中,使用非标准密钥大小的 RSA 证书的客户无法通过 System.Security.Cryptography.X509Certificates.RSACertificateExtensions.GetRSAPublicKey(X509Certificate2) 和 System.Security.Cryptography.X509Certificates.RSACertificateExtensions.GetRSAPrivateKey(X509Certificate2) 扩展方法访问这些密钥。 将引发 System.Security.Cryptography.CryptographicException 并显示消息“不支持所请求的密钥大小”。 .NET Framework 4.6.2 中已修复此问题。 同样,ImportParameters(RSAParameters) 和 ImportParameters(RSAParameters) 现在可以处理非标准密钥大小,而不会引发 System.Security.Cryptography.CryptographicException。
建议
如果处理依赖于先前行为的逻辑时有任何异常 - 使用非标准密钥大小时引发 System.Security.Cryptography.CryptographicException,请考虑删除该逻辑。
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6.2 |
类型 | 重定目标 |
受影响的 API
- RSA.ImportParameters(RSAParameters)
- RSACng.ImportParameters(RSAParameters)
- RSACertificateExtensions.GetRSAPrivateKey(X509Certificate2)
- RSACertificateExtensions.GetRSAPublicKey(X509Certificate2)
SignedXml.GetPublicKey 在 net462(或 lightup)上返回 RSACng 而不重定向更改
详细信息
从 .NET Framework 4.6.2 开始,SignedXml.GetPublicKey 方法所返回对象的具体类型从 CryptoServiceProvider 实现更改为 Cng 实现(不奇怪)。 这是因为实现已从使用 certificate.PublicKey.Key
更改为使用内部 certificate.GetAnyPublicKey
(将转到 RSACertificateExtensions.GetRSAPublicKey)。
建议
从在 .NET Framework 4.7.1 上运行的应用开始,可通过将以下配置开关添加到应用配置文件的运行时部分,使用 .NET Framework 4.6.1 和早期版本中默认使用的 CryptoServiceProvider 实现:
<AppContextSwitchOverrides value="Switch.System.Security.Cryptography.Xml.SignedXmlUseLegacyCertificatePrivateKey=true" />
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6.2 |
类型 | 重定目标 |
受影响的 API
Windows Communication Foundation (WCF)
使用可重入服务时可能导致死锁
详细信息
死锁可能会导致一个可重入服务,该服务将服务的实例一次限制为一个执行线程。 代码中包含以下 ServiceBehaviorAttribute 的服务容易遇到此问题:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
建议
要解决此问题,可执行以下操作:
- 将服务的并发模式设置为 ConcurrencyMode.Single 或 ConcurrencyMode.Multiple。 例如:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
- 安装 .NET Framework 4.6.2 的最新更新,或升级到更高版本的 .NET Framework。 这将在 OperationContext.Current 中禁用 ExecutionContext 的流。 此行为是可配置的;它相当于将以下应用设置添加到配置文件中:
<appSettings>
<add key="Switch.System.ServiceModel.DisableOperationContextAsyncFlow" value="true" />
</appSettings>
对于 Reentrant 服务,Switch.System.ServiceModel.DisableOperationContextAsyncFlow
的值绝不能设置为 false
。
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6.2 |
类型 | 重定目标 |
受影响的 API
OperationContext.Current 在 using 子句中被调用时可能返回 null
详细信息
如果满足以下所有条件,那么 OperationContext.Current 可能返回 null
且导致 NullReferenceException:
- 在返回 Task 或 Task<TResult> 的方法中检索 OperationContext.Current 属性的值。
- 在
using
子句中实例化 OperationContextScope 对象。 - 在
using statement
中检索 OperationContext.Current 属性的值。 例如:
using (new OperationContextScope(OperationContext.Current))
{
// OperationContext.Current is null.
OperationContext context = OperationContext.Current;
// ...
}
建议
要解决此问题,可执行以下操作:
按如下所示修改代码,实例化一个新的非
null
Current 对象:OperationContext ocx = OperationContext.Current; using (new OperationContextScope(OperationContext.Current)) { OperationContext.Current = new OperationContext(ocx.Channel); // ... }
安装 .NET Framework 4.6.2 的最新更新,或升级到更高版本的 .NET Framework。 这将禁用 OperationContext.Current 中的 ExecutionContext 流并还原 .NET Framework 4.6.1 以及更低版本中的 WCF 应用程序行为。 此行为是可配置的;它相当于将以下应用设置添加到配置文件中:
<appSettings> <add key="Switch.System.ServiceModel.DisableOperationContextAsyncFlow" value="true" /> </appSettings>
如果不需要此更改并且应用程序依赖操作上下文间的执行上下文流,那么可以启用它的流,如下所示:
<appSettings> <add key="Switch.System.ServiceModel.DisableOperationContextAsyncFlow" value="false" /> </appSettings>
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6.2 |
类型 | 重定目标 |
受影响的 API
WCF 传输安全性支持使用 CNG 存储的证书
详细信息
从面向 .NET Framework 4.6.2 的应用起,WCF 传输安全性支持使用 Windows 加密库 (CNG) 存储的证书。 此支持仅限于将证书与指数长度不超过 32 位的公钥结合使用。 当应用程序面向 .NET Framework 4.6.2 时,此功能默认启用。在旧版 .NET framework 中,尝试将 X509 证书与 CSG 密钥存储提供程序结合使用会引发异常。
建议
应用如果面向 .NET Framework 4.6.1 和更早版本,但在 .NET Framework 4.6.2 上运行,则可通过将以下行添加到 app.config 或 web.config 文件的 <runtime>
部分来启用对 CNG 证书的支持:
<runtime>
<AppContextSwitchOverrides value="Switch.System.IdentityModel.DisableCngCertificates=false" />
</runtime>
也可以使用以下代码以编程方式完成此操作:
private const string DisableCngCertificates = @"Switch.System.IdentityModel.DisableCngCertificate";
AppContext.SetSwitch(disableCngCertificates, false);
Const DisableCngCertificates As String = "Switch.System.IdentityModel.DisableCngCertificates"
AppContext.SetSwitch(disableCngCertificates, False)
请注意,鉴于有此更改,将不再执行任何依赖无法尝试使用 CNG 证书启动安全通信的异常处理代码。
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6.2 |
类型 | 重定目标 |
Windows 窗体
MemberDescriptor.Equals 实现不正确
详细信息
MemberDescriptor.Equals 方法的原始实现从比较类别名称和描述字符串这两个对象来比较两个不同字符串属性。 解决方法是比较第一个对象的 Category 和第二个对象的 Category,并比较第一个对象的 Description 和第二个对象的 Description。
建议
描述符相等时如果应用程序依赖于有时返回 false
的 MemberDescriptor.Equals 并且你面向 .NET Framework 4.6.2 和更高版本,那么可以采用以下几个选项:
- 除了调用 MemberDescriptor.Equals 方法,还需更改代码来手动比较 Category 和 Description 字段。
- 将以下值添加到 app.config 文件从而选择弃用此更改:
<runtime>
<AppContextSwitchOverrides value="Switch.System.MemberDescriptorEqualsReturnsFalseIfEquivalent=true" />
</runtime>
如果应用程序面向 .NET Framework 4.6.1 或更低版本,并且在 .NET Framework 4.6.2 及更高版本上运行且你想要启用此更改,可以通过将以下值添加到 app.config 文件以将兼容性开关设为 false
:
<runtime>
<AppContextSwitchOverrides value="Switch.System.MemberDescriptorEqualsReturnsFalseIfEquivalent=false" />
</runtime>
“属性” | 值 |
---|---|
范围 | 边缘 |
Version | 4.6.2 |
类型 | 重定目标 |
受影响的 API
Windows Presentation Foundation (WPF)
在 WPF 调度程序操作上不保留 CurrentCulture
详细信息
从 .NET Framework 4.6 开始,在 System.Windows.Threading.Dispatcher 中对 System.Globalization.CultureInfo.CurrentCulture 或 System.Globalization.CultureInfo.CurrentUICulture 的更改将会在该调度程序操作结束时丢失。 同样,在调度程序操作外对 System.Globalization.CultureInfo.CurrentCulture 或 System.Globalization.CultureInfo.CurrentUICulture 的更改在执行该操作时可能不会反映出来。实际上,这意味着 System.Globalization.CultureInfo.CurrentCulture 和 System.Globalization.CultureInfo.CurrentUICulture 更改可能不会在 WPF UI 回调和 WPF 应用程序中的其他代码之间流动。这是因为,从面向 .NET Framework 4.6 的应用开始,System.Threading.ExecutionContext 中的一项更改使 System.Globalization.CultureInfo.CurrentCulture 和 System.Globalization.CultureInfo.CurrentUICulture 存储在执行上下文中。 WPF 调度程序操作存储用于启动操作的执行上下文,并在操作完成时还原以前的上下文。 由于 System.Globalization.CultureInfo.CurrentCulture 和 System.Globalization.CultureInfo.CurrentUICulture 现在属于该上下文,因此,在调度程序操作中对它们所做的更改在操作之外不会保留。
建议
受此更改影响的应用可在字段中存储所需的 System.Globalization.CultureInfo.CurrentCulture 或 System.Globalization.CultureInfo.CurrentUICulture,并在所有调度程序操作正文(包括 UI 事件回调处理程序)中检查是否设置了正确的 System.Globalization.CultureInfo.CurrentCulture 和 System.Globalization.CultureInfo.CurrentUICulture。 或者,因为在此 WPF 更改之下的 ExecutionContext 更改仅影响面向 .NET Framework 4.6 或更高版本的应用,面向 .NET Framework 4.5.2 可避免出现此中断。面向 .NET Framework 4.6 或更高版本的应用也可以通过设置以下兼容性开关解决此问题:
AppContext.SetSwitch("Switch.System.Globalization.NoAsyncCurrentCulture", true);
.NET Framework 4.6.2 中的 WPF 已修复此问题。 .NET Frameworks 4.6、4.6.1 中也通过 KB 3139549 修复了此问题。 面向 .NET Framework 4.6 或更高版本的应用程序将自动在 WPF 应用程序中获取正确行为 - System.Globalization.CultureInfo.CurrentCulture/System.Globalization.CultureInfo.CurrentUICulture 将在调度程序操作中保留。
“属性” | 值 |
---|---|
范围 | 次要 |
Version | 4.6 |
类型 | 重定目标 |