适用于: .NET Framework
.NET
.NET Standard
AppContext 类允许 SqlClient 提供新的功能,同时继续支持依赖于先前行为的调用方。 用户可通过设置特定的 AppContext 开关来选择退出一种行为更改。
默认启用 MultiSubnetFailover
适用于:.NET Framework;.NET;.NET Standard
(从版本 7.0 开始可用)
若要全局设置 MultiSubnetFailover=true 而不修改单个连接字符串,可以在应用程序启动时将 AppContext 开关 “Switch.Microsoft.Data.SqlClient.EnableMultiSubnetFailoverByDefault” 设置为 true :
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.EnableMultiSubnetFailoverByDefault", true);
还可以在 App.Config 中启用此开关:
<runtime>
<AppContextSwitchOverrides value="Switch.Microsoft.Data.SqlClient.EnableMultiSubnetFailoverByDefault=true" />
</runtime>
启用后,所有连接的行为就像连接字符串中设置了 MultiSubnetFailover=true 参数一样。 默认情况下,此开关处于禁用状态。
为异步读取启用数据包复用
适用于:.NET Framework;.NET;.NET Standard
(从版本 7.0 开始可用)
数据包多路复用可提高大型异步读取操作的性能,例如 ExecuteReaderAsync 使用大型结果集、流式处理方案或批量数据检索。 此功能由两个选择加入 AppContext 开关控制。 将两个开关设置为 false 启用新的异步处理路径:
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseCompatibilityAsyncBehaviour", false);
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseCompatibilityProcessSni", false);
默认情况下,这两个开关都保留在true位置,从而保留现有(兼容)的行为。
启用用户代理功能扩展
适用于:.NET Framework;.NET;.NET Standard
(从版本 7.0 开始可用)
启用 AppContext 开关 “Switch.Microsoft.Data.SqlClient.EnableUserAgent” 时,驱动程序会将用户代理详细信息作为连接的一部分发送到服务器。 此信息有助于按版本和操作系统对驱动程序使用情况进行故障排除和量化。 默认情况下,此开关处于禁用状态。 若要启用它,请在应用程序启动时将 AppContext 开关设置为 true :
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.EnableUserAgent", true);
启用小数截断行为
适用于:.NET Framework;.NET;.NET Standard
从 Microsoft.Data.SqlClient 2.0 开始,与 SQL Server 一样,小数数据默认四舍五入。 若要启用之前的截断行为,可以在应用程序启动时将 AppContext 开关“Switch.Microsoft.Data.SqlClient.TruncateScaledDecimal”设置为 :
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.TruncateScaledDecimal", true);
在 Windows 上启用托管网络
适用于:.NET; .NET Standard
(仅从版本 2.0 开始可用)
在 Windows 上,SqlClient 默认使用 SNI 网络接口的本机实现。 若要支持使用托管 SNI 实现,可在应用程序启动时将 AppContext 开关“Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows”设置为 :
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", true);
此开关会切换驱动程序的行为,以便在 Windows 上的 .NET Core 2.1+ 和 .NET Standard 2.0+ 项目中使用托管的网络实现,从而消除对 Microsoft.Data.SqlClient 库的本机库的所有依赖项。 仅用于测试和调试目的。
注意
与本机实现相比,两者存在一些已知的差异。 例如,托管实现不支持非域 Windows 身份验证。
禁用透明网络 IP 解析
适用于:.NET Framework
透明网络 IP 解析 (TNIR) 是对现有 MultiSubnetFailover 功能的修订。 如果第一个解析的主机名 IP 未响应,且存在多个与主机名关联的 IP,TNIR 就会影响驱动程序的连接序列。 和MultiSubnetFailover的TransparentNetworkIPResolution组合选择了连接序列:
| 透明网络IP解析 | MultiSubnetFailover | 连接顺序 |
|---|---|---|
| 真 | 真 |
TransparentNetworkIPResolution 将被忽略。 驱动程序并行尝试DNS解析的IP地址,并与第一个响应者完成认证。 |
| 真 | 假 | 驱动程序会在DNS解析的IP地址上运行多次连接轮,首次尝试最低限度为500毫秒,超时次数逐渐增加,直到连接成功或达到总 Connect Timeout 连接。 |
| 假 | 真 | 驱动程序并行尝试DNS解析的IP地址,并与第一个响应者完成认证。 |
| 假 | 假 | 驱动程序依次尝试每个DNS解析的IP地址,直到成功或 Connect Timeout 达到某个地址。 |
TransparentNetworkIPResolution在 .NET Framework MultiSubnetFailover 中默认启用,默认情况下是禁用的。 在 .NET 5 及以后版本中,TransparentNetworkIPResolution没有识别的连接字符串关键字,设置它(任意值)都会抛ArgumentException出 (KeywordNotSupported)。 这些版本只对应尊重 MultiSubnetFailover 。 本节其余部分(自动覆盖、以下警告中的故障模式以及 AppContext 切换)适用于 .NET 框架。
小窍门
在每个连接字符串上设置MultiSubnetFailover=True,无论.NET版本如何,或目标是Azure SQL还是本地SQL Server。
MultiSubnetFailover=True 选择一条并行连接代码路径,快速找到第一个响应式副本。 在 .NET 框架上,它还绕过了 TNIR 的逐 IP 顺序重试循环,这也是导致连接延迟长和认证前握手超时的常见原因。
在 .NET 框架中,当 TransparentNetworkIPResolution 连接字符串 未指定时,驱动程序会自动禁用 TNIR,当数据源是已识别的 Azure SQL 端点,或Authentication将密钥设置为任意 Microsoft Entra ID 方法(Active Directory Password, Active Directory Device Code FlowActive Directory Service PrincipalActive Directory InteractiveActive Directory IntegratedActive Directory MSIActive Directory DefaultActive Directory Managed Identity或 Active Directory Workload Identity),或当SqlConnection.AccessToken属性被设置时。 关于驱动程序识别的端点后缀,请参见 TransparentNetworkIPResolutionSqlConnection.ConnectionString 中的条目。
显式值绕过了这种自动行为:True启用TransparentNetworkIPResolutionTNIR,False无条件禁用TNIR。 要恢复自动行为,请从连接字符串中移除关键词。 当连接字符串通过自定义的CNAME或vanity DNS名指向Azure SQL,且后缀未被识别为Azure SQL端点时,自动覆盖也不适用。 自动覆盖专门针对 Azure SQL;它不会触发本地 SQL Server,所以默认启用了 TNIR。
.NET框架上的长连接延迟
在 .NET 框架 TransparentNetworkIPResolution=True (默认设置)中,当目标 DNS 名称解析为多个 IP 且其中一个早期 IP 不健康、过时或无法访问时,可能会导致长时间连接延迟和认证前握手超时。 TNIR会依次尝试解决的IP地址,并每轮增加每次尝试的超时时间,直到达到总 Connect Timeout 值。 你通常会观察到一个意外长的连接延迟,最终导致以下错误:
Connection Timeout Expired. The timeout period elapsed while attempting to consume the pre-authentication handshake acknowledgement. This could be because the pre-authentication handshake failed or the server was unable to respond back in time.
该模式在几种拓扑中表现出来:
- Azure SQL 数据库、Azure SQL 托管实例,或 Microsoft Fabric 中的 SQL 数据库。 Azure SQL 网关将每个认证路由到后端副本。 当路由连接失败时,TNIR会重试路由后端,而不返回被重路由的网关,这会延长后端故障切换的延迟。
- 本地的 SQL Server 位于 Always On 可用性组监听器后面,该 DNS 名称解析为多个副本 IP。 在TNIR到达正常副本之前,会依次尝试过期的DNS条目或不健康的复盘IP。
-
带有多子网集群监听器的故障切换集群实例,或任何目标DNS名称包含多个
A/AAAA记录的配置(如DNS轮询)。
为避免此行为,在 连接字符串 中设置MultiSubnetFailover=True:
MultiSubnetFailover=True
该建议适用于所有 .NET 版本,涵盖 Azure SQL 和本地 SQL Server。 当 MultiSubnetFailover=True时,驱动程序忽略 TransparentNetworkIPResolution,尝试并行处理 DNS 解析的 IP 地址,并与第一个响应副本完成认证。 尽管名字 MultiSubnetFailover 是这样,但适用于任何DNS名称解析到多个目标IP的监听者,无论这些IP是否属于不同子网,且在独立服务器上,DNS解析到单个IP时是安全的。
为了实现进程范围的控制而不编辑每个连接字符串,可以使用默认的 AppContext 开关启用多子网故障切换。
用AppContext开关禁用TNIR
要在 .NET Framework 上将 from true 的默认值TransparentNetworkIPResolution翻转为 false ,请将 AppContext 切换Switch.Microsoft.Data.SqlClient.DisableTNIRByDefaultInConnectionString设置为true应用启动时。 该开关仅在 不在 连接字符串 中时更改默认值TransparentNetworkIPResolution;不会覆盖显式值。
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.DisableTNIRByDefaultInConnectionString", true);
有关设置这些属性的详细信息,请参阅 SqlConnection.ConnectionString 属性文档。
在登录期间启用最小超时
适用于:.NET Framework;.NET;.NET Standard
若要防止登录尝试无期限等待,可在应用程序启动时将 AppContext 开关“Switch.Microsoft.Data.SqlClient.UseOneSecFloorInTimeoutCalculationDuringLogin”设置为 true:
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseOneSecFloorInTimeoutCalculationDuringLogin", false);
禁用 ReadAsync 的阻止行为
适用于:.NET Framework;.NET;.NET Standard
从版本 3.0 开始,ReadAsync 以异步方式运行。 以前的版本以同步方式运行 ReadAsync,并阻止 .NET Framework 上的调用线程。 若要控制此阻止行为,可在应用程序启动时将 AppContext 开关“Switch.Microsoft.Data.SqlClient.MakeReadAsyncBlocking”设置为 或 true:
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.MakeReadAsyncBlocking", false);
启用行版本 null 行为
适用于:.NET Framework;.NET;.NET Standard
从版本 3.0 开始,当行版本的值为 null 时,SqlDataReader 会返回 DBNull 值而不是空的 byte[]。 要启用返回空占位符byte[]的旧版行为,请在应用程序启动时启用 AppContext 开关 Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior。
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior", true);
禁止显示不安全的 TLS 警告
适用于:.NET Framework;.NET;.NET Standard
(从版本 4.0.1 开始可用)
在连接字符串中使用 Encrypt=false 时,如果 TLS 版本为 1.2 或更低版本,则安全警告将输出到控制台。 可以通过在应用程序启动时启用以下 AppContext 开关来禁止显示此警告:
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.SuppressInsecureTLSWarning", true);
忽略服务器指定的故障切换伙伴
适用于:.NET Framework;.NET;.NET Standard
(从版本 5.1.8、6.0.4 和 6.1.3 开始可用)
故障转移后,服务器提供的故障转移伙伴信息优先于连接字符串中提供的故障转移伙伴信息。 若要忽略服务器提供的故障转移伙伴信息,并且只考虑连接字符串中提供的故障转移伙伴信息,请启用应用程序启动时的此 AppContext 开关:
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.IgnoreServerProvidedFailoverPartner", true);