Comutadores de AppContext em SqlClient

Aplica-se a: .NET Framework .NET .NET Standard

Baixar ADO.NET

A classe AppContext permite que SqlClient forneça novas funcionalidades enquanto continua a oferecer suporte a chamadores que dependem do comportamento anterior. Os usuários podem desativar uma alteração no comportamento definindo opções específicas do AppContext.

O SqlClient lê e armazena em cache cada switch na primeira vez que usa esse switch. Configure as opções no arranque da aplicação, antes de utilizar quaisquer tipos de SqlClient. Mudar um switch depois de o SqlClient ter armazenado o seu valor em cache não tem efeito.

Ativar MultiSubnetFailover por padrão

Aplica-se a: .NET Framework; .NET; .NET Standard

(Disponível a partir da versão 7.0)

Para definir MultiSubnetFailover=true globalmente sem modificar as cadeias de ligação individuais, defina o comutador Switch.Microsoft.Data.SqlClient.EnableMultiSubnetFailoverByDefault AppContext para true no arranque da aplicação:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.EnableMultiSubnetFailoverByDefault", true);

Também podes ativar este interruptor na tua App.Config:

<runtime>
  <AppContextSwitchOverrides value="Switch.Microsoft.Data.SqlClient.EnableMultiSubnetFailoverByDefault=true" />
</runtime>

Quando ativadas, todas as ligações comportam-se como se MultiSubnetFailover=true estivessem definidas na cadeia de ligação. Este interruptor está desativado por defeito.

Ativar multiplexação de pacotes para leituras assíncronas

Aplica-se a: .NET Framework; .NET; .NET Standard

(Disponível a partir da versão 7.0)

A multiplexação de pacotes melhora o desempenho para grandes operações de leitura assíncrona, como ExecuteReaderAsync em grandes conjuntos de resultados, cenários de streaming ou recuperação massiva de dados. Esta funcionalidade é controlada por dois interruptores AppContext opt-in. Configurar ambos os switches para false ativa o novo caminho de processamento assíncrono:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseCompatibilityAsyncBehaviour", false);
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseCompatibilityProcessSni", false);

Por defeito, ambos os switches são true, o que preserva o comportamento existente (compatível).

Habilitar o comportamento de truncamento decimal

Aplica-se a: .NET Framework; .NET; .NET Standard

A partir de Microsoft.Data.SqlClient 2.0, os dados decimais são arredondados por padrão, como é feito pelo SQL Server. Para ativar o comportamento anterior de truncamento, pode definir o interruptor Switch.Microsoft.Data.SqlClient.TruncateScaledDecimal AppContext para true no arranque da aplicação:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.TruncateScaledDecimal", true);

Habilitar rede gerenciada no Windows

Aplica-se a: .NET; .NET Standard

(Disponível a partir da versão 2.0)

No Windows, SqlClient usa uma implementação nativa da interface de rede SNI por padrão. Para permitir a utilização de uma implementação SNI gerida, defina o comutador Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows AppContext para true no arranque da aplicação:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", true);

Essa opção alterna o comportamento do driver para usar uma implementação de rede gerenciada em projetos .NET Core 2.1+ e .NET Standard 2.0+ no Windows, eliminando todas as dependências em bibliotecas nativas para a biblioteca Microsoft.Data.SqlClient. É apenas para fins de teste e depuração.

Observação

Existem algumas diferenças conhecidas quando comparado com a implementação nativa. Por exemplo, a implementação gerida não suporta Autenticação Windows fora do domínio.

Desativar a Resolução Transparente de IP de Rede

Aplica-se a: .NET Framework

A Resolução IP de Rede Transparente (TNIR) é uma revisão do recurso MultiSubnetFailover existente. TNIR afeta a sequência de conexão do driver no caso em que o primeiro IP resolvido do nome do host não responde e há vários IPs associados ao nome do host. A combinação de TransparentNetworkIPResolution e MultiSubnetFailover seleciona a sequência de ligação:

TransparentNetworkIPResolution MultiSubnetFailover Sequência de ligação
Verdade Verdade TransparentNetworkIPResolution é ignorado. O driver tenta os endereços IP resolvidos por DNS em paralelo e conclui a autenticação com o primeiro respondedor.
Verdade Falso O controlador executa múltiplas rondas de tentativa de ligação entre os endereços IP resolvidos pelo DNS, com um mínimo de 500 milissegundos na primeira tentativa e tempos limite por tentativa progressivamente maiores, até que uma ligação seja bem-sucedida ou que o Connect Timeout global seja atingido.
Falso Verdade O driver tenta os endereços IP resolvidos por DNS em paralelo e conclui a autenticação com o primeiro respondedor.
Falso Falso O driver tenta cada endereço IP resolvido por DNS sequencialmente até que um tenha sucesso ou Connect Timeout seja alcançado.

TransparentNetworkIPResolutionestá ativado por defeito no .NET Framework e MultiSubnetFailover está desativado por defeito. No .NET 5 e em versões posteriores, TransparentNetworkIPResolution não é uma palavra‑chave reconhecida de uma cadeia de ligação e a sua definição (com qualquer valor) gera ArgumentException (KeywordNotSupported). Estas versões respeitam apenas MultiSubnetFailover. O restante desta secção (a sobreposição automática, os modos de falha no aviso seguinte e o interruptor AppContext) aplica-se ao .NET Framework.

Sugestão

Defina MultiSubnetFailover=True em todas as cadeias de ligação, independentemente da versão do .NET ou de o destino ser o SQL do Azure ou o SQL Server no local. MultiSubnetFailover=True seleciona um percurso de código de ligação em paralelo que encontra rapidamente a primeira réplica que responde. No .NET Framework, também contorna o ciclo sequencial de repetição por IP do TNIR, que é uma causa comum de longos atrasos de ligação e tempos limite do handshake de pré-autenticação.

No .NET Framework, quando TransparentNetworkIPResolution não está especificado na cadeia de ligação, o controlador desativa automaticamente o TNIR quando a origem de dados é um ponto final reconhecido do SQL do Azure, quando a chave Authentication está definida para qualquer método do Microsoft Entra ID (Active Directory Password, Active Directory Integrated, Active Directory Interactive, Active Directory Service Principal, Active Directory Device Code Flow, Active Directory Managed Identity, Active Directory MSI, Active Directory Default ou Active Directory Workload Identity), ou quando a propriedade SqlConnection.AccessToken está definida. Para os sufixos de endpoint que o controlador reconhece, consulte a entrada TransparentNetworkIPResolution em SqlConnection.ConnectionString.

Um valor explícito TransparentNetworkIPResolution contorna este comportamento automático: True ativa o TNIR e False desativa o TNIR incondicionalmente. Para restaurar o comportamento automático, remova a palavra-chave da cadeia de ligação. A sobreposição automática também não se aplica quando a cadeia de ligação aponta para o SQL do Azure através de um CNAME personalizado ou de um nome DNS personalizado cujo sufixo não é reconhecido como um endpoint do SQL do Azure. A substituição automática destina-se especificamente ao SQL do Azure; não se aplica ao SQL Server no local, pelo que o TNIR fica ativado por predefinição.

Longos atrasos de ligação no .NET Framework

No .NET Framework, TransparentNetworkIPResolution=True (o predefinido) pode causar longos atrasos no estabelecimento da ligação e tempos limite no handshake de pré-autenticação sempre que o nome DNS de destino for resolvido para vários endereços IP e um dos primeiros endereços IP estiver indisponível, desatualizado ou inacessível. O TNIR tenta sequencialmente os endereços IP resolvidos e aumenta o tempo limite por tentativa a cada ronda até ser atingido o Connect Timeout global. Normalmente, observa um atraso de ligação inesperadamente longo que termina neste erro:

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.

O padrão aparece em várias topologias:

  • Base de Dados SQL do Azure, Azure SQL Managed Instance ou base de dados SQL no Microsoft Fabric. O gateway do SQL do Azure encaminha cada autenticação para uma réplica de back-end. Quando uma ligação com encaminhamento falha, o TNIR tenta novamente o backend de destino sem voltar ao gateway para ser reencaminhado, o que aumenta a latência durante uma comutação por falha do backend.
  • SQL Server on-premises por trás de um escutador de um grupo de disponibilidade Always On cujo nome DNS é resolvido para múltiplos endereços IP de réplica. Uma entrada DNS obsoleta ou uma réplica IP não saudável é testada sequencialmente antes de o TNIR chegar a uma réplica funcional.
  • Instâncias de cluster de failover com um ouvinte de cluster multi-subnet, ou qualquer outra configuração onde o nome DNS alvo tenha múltiplos A/AAAA registos (como o round-robin DNS).

Para evitar este comportamento, defina MultiSubnetFailover=True na cadeia de ligação:

MultiSubnetFailover=True

Esta recomendação funciona em todas as versões de .NET e abrange tanto SQL do Azure como SQL Server on-premiss. Quando MultiSubnetFailover=True, o driver ignora TransparentNetworkIPResolution, tenta os endereços IP resolvidos por DNS em paralelo e conclui a autenticação com a primeira réplica responsiva. Apesar do nome, MultiSubnetFailover aplica-se a qualquer ouvinte cujo nome DNS resolva para múltiplos IPs-alvo, independentemente de esses IPs estarem em sub-redes diferentes, e é seguro em servidores autónomos cujo DNS resolve para um único IP.

Para um controlo ao nível de todo o processo sem editar todas as cadeias de ligação, use o comutador AppContext Enable MultiSubnetFailover by default.

Desativar o TNIR com uma opção AppContext

Para inverter o valor padrão de TransparentNetworkIPResolution de true para false no .NET Framework, defina o interruptor Switch.Microsoft.Data.SqlClient.DisableTNIRByDefaultInConnectionString AppContext para true no arranque da aplicação. Este switch só altera o valor padrão quando TransparentNetworkIPResolution não está na cadeia de ligação; não sobrepõe um valor explícito.

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.DisableTNIRByDefaultInConnectionString", true);

Para obter mais informações sobre como definir essas propriedades, consulte a documentação da propriedade SqlConnection.ConnectionString.

Desative o tempo limite mínimo durante o login

Aplica-se a: .NET Framework; .NET; .NET Standard

Por defeito, o SqlClient impõe um mínimo de um segundo ao calcular o tempo disponível para uma tentativa de login. Este comportamento impede que uma tentativa de login espere indefinidamente quando o timeout calculado é arredondado para zero.

Para restaurar o comportamento legado, defina o interruptor Switch.Microsoft.Data.SqlClient.UseOneSecFloorInTimeoutCalculationDuringLogin AppContext para false no arranque da aplicação:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseOneSecFloorInTimeoutCalculationDuringLogin", false);

Desativar o comportamento de bloqueio do ReadAsync

Aplica-se a: .NET Framework; .NET; .NET Standard

A partir da versão 3.0, ReadAsync corre de forma assíncrona. As versões anteriores correm ReadAsync de forma síncrona e bloqueiam o thread de chamada no .NET Framework. Para controlar este comportamento de bloqueio, defina o comutador Switch.Microsoft.Data.SqlClient.MakeReadAsyncBlocking AppContext para true ou false no arranque da aplicação:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.MakeReadAsyncBlocking", false);

Ativar comportamento nulo de rowversion

Aplica-se a: .NET Framework; .NET; .NET Standard

A partir da versão 3.0, quando uma rowversion tem um valor nulo, SqlDataReader devolve um DBNull valor em vez de um vazio byte[]. Para ativar o comportamento legado de devolver um byte[] vazio, ative o comutador AppContext Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior no arranque da aplicação.

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior", true);

Suprimir aviso TLS inseguro

Aplica-se a: .NET Framework; .NET; .NET Standard

(Disponível a partir da versão 4.0.1)

Ao usar Encrypt=false na cadeia de ligação, a consola emite um aviso de segurança se a versão do TLS for 1.2 ou inferior. Suprima este aviso ativando o seguinte interruptor AppContext no arranque da aplicação:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.SuppressInsecureTLSWarning", true);

Ignorar parceiro de failover especificado pelo servidor

Aplica-se a: .NET Framework; .NET; .NET Standard

(Disponível a partir das versões 5.1.8, 6.0.4 e 6.1.3)

Após o failover, as informações do parceiro de failover fornecidas pelo servidor têm preferência sobre as informações do parceiro de failover fornecidas na string de conexão. Para ignorar as informações do parceiro de failover fornecidas pelo servidor e considerar apenas as informações do parceiro de failover fornecidas na string de conexão, habilite esta opção AppContext na inicialização da aplicação:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.IgnoreServerProvidedFailoverPartner", true);

Impor o timeout de inatividade da ligação

Aplica-se a: .NET Framework; .NET; .NET Standard

A partir da versão 7.1.0, a palavra‑chave da cadeia de ligação SqlConnectionStringBuilder.IdleTimeout e a propriedade Connection Idle Timeout configuram verificações de expiração por inatividade e limpeza em segundo plano para ligações em pool. O valor predefinido é 300 segundos. Valores negativos geram uma ArgumentException.

A configuração do switch e da cadeia de ligação afetam cada implementação de pool de forma diferente:

  • Piscina V1. Quando o interruptor é true, V1 usa a sua cadência histórica aleatória de limpeza de dois a quatro minutos e elimina as ligações ociosas independentemente de Connection Idle Timeout. Quando o interruptor é false e Connection Idle Timeout é diferente de zero, o V1 usa metade do timeout configurado como cadência de limpeza e remove as ligações inativas após um ou dois ciclos de limpeza. Quando o comutador é false e Connection Idle Timeout=0, V1 desativa a expulsão de inatividade, mas continua a manutenção do tamanho mínimo do pool no intervalo histórico aleatório de dois a quatro minutos.
  • pool V2. Quando o switch é true, V2 não realiza verificações de idade ociosa por ligação, mas um valor Connection Idle Timeout diferente de zero ativa e configura a poda em segundo plano. Quando o switch é false e Connection Idle Timeout é diferente de zero, o V2 realiza verificações de idade ociosa por conexão e configura a poda em segundo plano a partir do timeout. Quando o switch é false e Connection Idle Timeout=0, a V2 não realiza verificações de idade ociosa por ligação nem poda em segundo plano. V2 não realiza eliminação em segundo plano quando Min Pool Size é maior ou igual a Max Pool Size.
AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseLegacyIdleTimeoutBehavior", false);

Para exemplos de configuração, veja Limitar o tempo de inatividade da ligação.

Ativar o agrupamento de ligações V2

Aplica-se a: .NET Framework; .NET; .NET Standard

A partir da versão 7.1, o SqlClient inclui uma implementação alternativa de pool de ligação (V2). O pool V1 mantém-se como padrão, e o switch fica por defeito em false.

Para optar pela V2, ative o comutador Switch.Microsoft.Data.SqlClient.UseConnectionPoolV2 AppContext quando a aplicação iniciar:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseConnectionPoolV2", true);

Os controlos de pooling de cadeia de ligação aplicam-se a ambas as implementações. Para mais informações, consulte o agrupamento de ligações do SQL Server.

Use um único timeout de ligação para esperas de pool e ligações de rede

Aplica-se a: .NET Framework; .NET; .NET Standard

A partir da versão 7.1.0, o tempo gasto à espera de uma ligação do pool pode contar para o orçamento do Connect Timeout chamador, pelo que a espera no pool e a tentativa de ligação à rede partilham um timeout total. Ative Switch.Microsoft.Data.SqlClient.UseOverallConnectTimeoutForPoolWait para usar o timeout global com qualquer uma das implementações do pool de ligações:

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseOverallConnectTimeoutForPoolWait", true);

O interruptor fica definido por predefinição para false. Este padrão preserva o comportamento legado de timeout da ligação, onde a operação do pool recebe um Connect Timeout completo e a tentativa de ligação de rede recebe outro timeout completo. Como resultado, Open ou OpenAsync podem demorar mais tempo do que o configurado Connect Timeout.

Reverter à alternância de failover legado em caso de erros de login

Aplica-se a: .NET Framework; .NET; .NET Standard

A partir da versão 7.1.0, ao ligar com failover configurado, o SqlClient deixa de alternar para o parceiro de failover para erros SQL devolvidos durante a fase de login. Para voltar ao comportamento legado de alternância, ative o comutador AppContext Switch.Microsoft.Data.SqlClient.UseLegacyFailoverAlternationOnLoginSqlErrors no arranque da aplicação. O interruptor fica definido por predefinição para false.

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseLegacyFailoverAlternationOnLoginSqlErrors", true);

Respeitar uma escala explicitamente definida para zero para os parâmetros vartime

Aplica-se a: .NET Framework; .NET; .NET Standard

Por predefinição, o SqlClient envia uma escala de 7 quando define explicitamente a escala como 0 para parâmetros datetime2, datetimeoffset ou time. Na versão 6.0 ou posterior, definir Switch.Microsoft.Data.SqlClient.LegacyVarTimeZeroScaleBehaviour para false no arranque da aplicação para preservar a escala explícita de 0. O interruptor fica definido por predefinição para true.

AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.LegacyVarTimeZeroScaleBehaviour", false);