Compartilhar via


As práticas recomendadas de confiabilidade

As seguintes regras de confiabilidade são orientadas para SQL Server; No entanto, eles também se aplicam a qualquer aplicativo de servidor baseado em host. É extremamente importante que os servidores como, por exemplo, SQL Server não vazam recursos e não ficar inoperante. No entanto, isso não é possível escrever código de back-out para cada método que altera o estado do objeto. O objetivo é não escrever 100 por cento confiável código gerenciado que irá recuperar de erros em cada local com o código de back-out. Essa seria uma tarefa desanimadora com pouca chance de sucesso. O common language runtime (CLR) não pode fornecer facilmente garantias suficientemente fortes para código gerenciado para tornar a escrever código de perfeito viável. Observe que, diferentemente do ASP.NET, o SQL Server usa somente um processo que não pode ser reciclado sem interromper um banco de dados para um período de tempo inaceitável.

Com essas garantias mais fracas e em execução em um único processo, a confiabilidade baseia-se em segmentos de terminação ou reciclagem de domínios de aplicativos quando necessárias e afastamento precauções para garantir que os recursos de sistema operacional, como identificadores ou memória não sejam perdidas. Mesmo com essa restrição mais simples de confiabilidade, ainda há um requisito de confiabilidade significativos:

  • Nunca os recursos de sistema operacional vazamento.

  • Identifica os bloqueios todas gerenciados em todos os formulários para o CLR.

  • Nunca o domínio entre aplicativos quebra compartilhado de estado, permitindo que AppDomain reciclagem para funcionar perfeitamente.

Embora seja teoricamente possível escrever código gerenciado para lidar com ThreadAbortException, StackOverflowException, e OutOfMemoryException exceções, esperando os desenvolvedores escrevam tal código robusto em todo um aplicativo é razoável. Por esse motivo, as exceções de out-of-band resultar no segmento que está sendo encerrado; e se finalizou o thread estava editando o estado compartilhado, que pode ser determinado se o thread mantém um bloqueio, em seguida, a AppDomain é descarregado. Quando um método que está editando o estado compartilhado é finalizado, o estado estar corrompido porque não é possível escrever código confiável de back-out para atualizações para o estado compartilhado.

No.NET Framework versão 2.0, o host único que requer a confiabilidade é SQL Server. Se o assembly será executado em SQL Server, você deve fazer o trabalho de confiabilidade para todas as partes do assembly, mesmo se houver recursos específicos que são desativados quando executado no banco de dados. Isso é necessário porque o mecanismo de análise de código examina o código no nível do assembly e não consegue diferenciar o código desativado. De SQL Server outra consideração de programação é SQL Server tudo em um processo, e AppDomain a reciclagem é usada para limpar todos os recursos como memória e sistema operacional alças.

Você não pode depender de finalizadores ou destruidores ou try/finally blocos de código de back-out. Pode ser interrompidas ou não chamados.

Exceções assíncronas podem ser lançadas em locais inesperados, possivelmente cada instrução da máquina: ThreadAbortException, StackOverflowException, and OutOfMemoryException.

Threads gerenciados não são necessariamente os segmentos de Win32 no SQL; eles podem ser fibras.

Estado compartilhado mutável de domínio entre aplicativos ou de todo o processo é extremamente difícil alterar com segurança e deve ser evitado sempre que possível.

Condições de falta de memória não são raras no SQL Server.

Se hospedado no SQL Server de bibliotecas não atualizam corretamente o estado compartilhado, há uma grande probabilidade de que o código não recuperará até que o banco de dados foi reiniciado. Além disso, em alguns casos extremos, é possível que isso pode causar falha, o processo de SQL Server, fazendo com que o banco de dados reinicializar. Reinicializar o banco de dados pode levar para baixo de um site da Web ou afetar as operações da empresa, afetando a disponibilidade. Um vazamento lento dos recursos do sistema operacional, como memória ou alças pode causar falha eventualmente a alocar alças com nenhuma possibilidade de recuperação no servidor ou potencialmente o servidor lento pode degradar o desempenho e reduz a disponibilidade de aplicativos do cliente. Claramente, queremos evitar essas situações.

Regras de práticas recomendadas

A introdução voltado capturar para aumentar a estabilidade e confiabilidade do framework teria a revisão de código para código gerenciado executado no servidor. Todas essas verificações são uma boa prática em geral e um absoluto necessário no servidor.

No caso de uma restrição de bloqueio ou recurso inativa, SQL Server anular um thread ou subdividir um AppDomain. Quando isso acontece, o código de back-out somente em uma região de execução restrita (CER) é garantido para ser executado.

Usar o SafeHandle para evitar a perda de recursos

No caso de um AppDomain unload, você não pode depender finally blocos ou finalizadores sendo executados, por isso é importante para todos os acessos de recursos de sistema operacional através de abstrair a SafeHandle classe em vez de IntPtr, HandleRef, ou classes semelhantes. Isso permite que o CLR rastrear e fechar as alças de você usar o mesmo do AppDomain caso de subdivisão. SafeHandleusará um finalizador crítico que o CLR sempre será executado.

O identificador do sistema operacional é armazenado na SafeHandle desde o momento em que ele é criado até o momento em que ele seja liberado. Não há nenhuma janela durante o qual um ThreadAbortException pode ocorrer a perda de um identificador. Além disso, invocação de plataforma será-contagem de referência a alça, o que permite que o fechamento de controle de tempo de vida da alça, impedindo que um problema de segurança com uma condição de corrida entre Dispose e um método que está usando a alça.

A maioria das classes que atualmente têm um finalizador para simplesmente limpar um sistema operacional, manipular não precisará mais o finalizador. Em vez disso, o finalizador será o SafeHandle derivado da classe.

Observe que SafeHandle não substitui a IDisposable.Dispose. Existem recursos ainda possíveis vantagens de desempenho e a contenção descartar explicitamente os recursos do sistema operacional. Basta perceber que finally blocos que explicitamente descartar os recursos não podem executar para conclusão.

SafeHandlepermite que você implemente suas próprias ReleaseHandle método que executa o trabalho para liberar o identificador, como a passagem do estado de um identificador de sistema operacional, liberando a rotina ou liberando um conjunto de alças em um loop. O CLR garante que esse método é executado. É responsabilidade do autor do ReleaseHandle implementação para garantir que o identificador é liberado em todas as circunstâncias. Falha ao fazer isso fará com que a alça de vazamento, o que normalmente resulta no vazamento de recursos nativos associados com a alça. Por isso é fundamental para a estrutura SafeHandle classes derivadas que o ReleaseHandle implementação não requer a alocação dos recursos que podem não estar disponíveis no momento de invocação. Observe que é permitido chamar os métodos que podem falhar na implementação de ReleaseHandle desde que seu código pode lidar com tais falhas e concluir o contrato para liberar o identificador nativo. Para depuração, ReleaseHandle tem um Boolean retornar o valor que pode ser definida para false se for encontrado um erro de catastrófico que impedirá a liberação do recurso. Isso ativará o releaseHandleFailed MDA MDA, se ativado, para ajudar a identificar o problema. Ele não afeta o tempo de execução de qualquer outra forma; ReleaseHandlenão será chamado novamente para o mesmo recurso e, conseqüentemente, o identificador será perdido.

SafeHandlenão é apropriado em determinados contextos. Desde que o ReleaseHandle método pode ser executado em um GC thread do finalizador, os identificadores que são necessários para ser liberado em um determinado segmento não devem ser dispostos em um SafeHandle.

Runtime callable wrappers (RCWs) podem ser limpos pelo CLR sem código adicional. Para o código que usa a plataforma chamar e trata de um objeto COM como um IUnknown* ou um IntPtr, o código deve ser reescrito para usar um RCW. SafeHandlepode não ser adequado para esse cenário devido à possibilidade de um método de lançamento não gerenciado chamar código gerenciado.

Regra de análise de código

Use SafeHandle para encapsular a recursos de sistema operacional. Não use HandleRef ou campos do tipo IntPtr.

Certifique-se de finalizadores não precisam executar para impedir o vazamento de recursos do sistema operacional

Revise os finalizadores cuidadosamente para garantir que mesmo se eles não são executados, um recurso de críticos do sistema operacional não é perdido. Ao contrário de um normal AppDomain descarregar quando o aplicativo está em execução em um estado estável ou quando um servidor, como o SQL Server for desligado, objetos não são finalizadas durante um abrupto AppDomain unload. Certifique-se de recursos não são vazados no caso de um descarregamento abrupto, desde que a correção de um aplicativo não pode ser garantida, mas a integridade do servidor deve ser mantida por não vazamento de recursos. Use SafeHandle para liberar recursos de sistema operacional.

Certifique-se que finalmente cláusulas não precisa executar para impedir o vazamento de recursos de sistema operacional

finallycláusulas não são garantidas executado fora das CERs, exigindo que os desenvolvedores de bibliotecas não dependem de código dentro de um finally bloco para liberar recursos não gerenciados. Usando SafeHandle é a solução recomendada.

Regra de análise de código

Use SafeHandle para limpar os recursos de sistema operacional em vez de Finalize. Não use IntPtr; Use SafeHandle para encapsular recursos. Se o finalmente cláusula deve ser executado, coloque-o em uma CER.

Todos os bloqueios devem passar pelo código de bloqueio gerenciado existente

O CLR precisa saber quando o código está em um bloqueio para que saibam para subdividir o AppDomain em vez de simplesmente anulá thread. Anular o segmento pode ser perigoso, como os dados operados pelo thread poderiam ser deixados em estado inconsistente. Portanto, todo o AppDomain tem que ser reciclado. As conseqüências da falha identificar um bloqueio podem ser deadlocks ou resultados incorretos. Use os métodos BeginCriticalRegion e EndCriticalRegion para identificar áreas de bloqueio. Eles estão métodos estáticos na Thread classe que se aplicam somente ao segmento atual, ajudando a impedir que um segmento da edição de contagem de bloqueio de outro thread.

Entere Exit tem esta notificação de CLR incorporada, portanto, sua utilização é recomendada, bem como o uso da <>bloqueio de>instrução (referência de TRANSLATION FROM VPE FOR CSHARP), que usa esses métodos.

Outros mecanismos de bloqueio como, por exemplo, bloqueios de rotação e AutoResetEvent deve chamar estes métodos para notificar o CLR se uma seção crítica está sendo inserida. Esses métodos não terão nenhum bloqueio; eles informam que o CLR que o código está em execução em uma seção crítica e anular o thread poderia deixar estado compartilhado inconsistente. Se você tiver definido o seu próprio tipo de bloqueio, como, por exemplo, um personalizado ReaderWriterLock classe, usar esses métodos de contagem de bloqueio.

Regra de análise de código

Marcar e identificar todos os bloqueios usando BeginCriticalRegion e EndCriticalRegion. Não use CompareExchange, Increment, e Decrement em um loop. Não faça uma plataforma chamar das variantes do Win32 desses métodos. Não use Sleep em um loop. Não use campos volátil.

Limpar o código deve estar entre um finalmente ou um catch bloco, não seguir um catch

Código de limpeza nunca deve seguir um catch bloco; ele deve estar em um finally ou do catch próprio bloco. Isso deve ser uma boa prática normal. A finally bloco é geralmente preferido, pois o mesmo código executa quando uma exceção é lançada e quando o final da try block normalmente é encontrado. No caso de uma exceção inesperada que está sendo lançada, por exemplo um ThreadAbortException, o código de limpeza irá executar. Qualquer não gerenciados recursos que você deseja limpar em um finally o ideal é que deve ser disposto em um SafeHandle para evitar vazamentos. Observe o C# using palavra-chave pode ser usada com eficiência para descartar objetos, incluindo alças.

Embora AppDomain a reciclagem pode limpar os recursos no thread do finalizador, ainda é importante colocar o código de limpeza no lugar correto. Observe que, se um thread recebe uma exceção assíncrona sem mantendo um bloqueio, o CLR tenta encerrar o segmento sem a necessidade de reciclar o AppDomain. Garantir que recursos são limpos mais cedo em vez de ajuda mais recente por disponibilizar mais recursos e melhor gerenciar a vida útil. Se você não fechar explicitamente um identificador para um arquivo em algum caminho de código de erro, em seguida, aguarde a SafeHandle finalizador para limpá-lo, na próxima vez em que seu código é executado pode falhar, tentando acessar exatamente o mesmo arquivo, se o finalizador tiver ainda não esteja a executar. Por esse motivo, garantindo que o código de limpeza existe e funciona corretamente ajudará a recuperar de falhas mais limpa e rapidamente, embora não seja estritamente necessário.

Regra de análise de código

Código de limpeza após catch precisa estar em um finally bloco. Colocar chamadas a dispose em um bloco finally. catchblocos devem terminar com uma throw ou relançar. Embora haja exceções, como, por exemplo, código de detecção se pode ser estabelecida uma conexão de rede onde você pode receber qualquer um grande número de exceções, qualquer código que requer que a captura de um número de exceções em circunstâncias normais deve fornecer uma indicação de que o código deve ser testado para ver se ele terá êxito.

Estado compartilhado mutável em todo o processo entre domínios de aplicativo deve ser eliminada ou usar uma região de execução restrita

Conforme descrito na introdução, pode ser muito difícil escrever código gerenciado que monitora o estado de todo o processo compartilhado entre domínios de aplicativo de maneira confiável. Todo o processo estado compartilhado é qualquer tipo de estrutura de dados compartilhado entre domínios de aplicativos, no código do Win32, dentro do CLR, ou em código gerenciado usando o sistema de interação remota. Qualquer estado compartilhado mutável é muito difícil gravar corretamente no código gerenciado e qualquer estado compartilhado estático pode ser feito apenas com muito cuidado. Se você tem todo o processo ou de máquina de estado compartilhado, encontre alguma maneira para eliminá-lo ou proteger o estado compartilhado usando uma região de execução restrita (CER). Observe que qualquer biblioteca com o estado compartilhado que não identificada e corrigida poderia causar um host, como, por exemplo, SQL Server, que requer a limpeza AppDomain descarregando para travamento.

Se o código usa um objeto COM, evite o compartilhamento desse objeto COM entre domínios de aplicativo.

Bloqueios não funcionar, todo o processo ou entre domínios de aplicativo.

No passado, Enter e <>bloqueio de>instrução (referência de TRANSLATION FROM VPE FOR CSHARP) foram usados para criar o processo global bloqueios. Por exemplo, isso ocorre quando o bloqueio no AppDomain ágil classes, como Type instâncias de assemblies não compartilhado, Thread objetos, seqüências de caracteres interned e algumas cadeias de caracteres compartilhada entre domínios de aplicativo usando o sistema de interação remota. Esses bloqueios não são mais todo o processo. Para identificar a presença de um bloqueio de todo o processo de domínio entre aplicativos, determine se o código dentro do bloqueio usa qualquer recurso externo, persistente, como um arquivo no disco ou, possivelmente, um banco de dados.

Observe que um bloqueio dentro de tirar uma AppDomain pode causar problemas se o código protegido usa um recurso externo, porque esse código poderá ser executado simultaneamente em vários domínios de aplicativo. Isso pode ser um problema ao gravar um arquivo de log ou vinculação a um soquete para todo o processo. Essas alterações significam que não há nenhuma maneira fácil, usando código gerenciado, para obter um bloqueio global do processo, além de usar um nome de Mutex ou Semaphore instância. Criar código que não é executado em dois domínios de aplicativo simultaneamente, ou use o Mutex ou Semaphore classes. Se o código existente não pode ser alterado, não use Win32 mutex denominado para atingir essa sincronização porque executando no modo fibra significa que você não pode garantir o mesmo thread do sistema operacional irá adquirir e liberar um mutex. Você deve usar o gerenciado Mutex classe, ou um nomeado ManualResetEvent, AutoResetEvent, ou um Semaphore para sincronizar o bloqueio de código de forma que o CLR é atento em vez de sincronização do bloqueio usando código não gerenciado.

Evite lock(typeof(MyType))

Públicos e privados Type objetos em assemblies compartilhados com apenas uma cópia do código é compartilhado entre todos os aplicativos domínios presentes também problemas. Para módulos (assemblies) compartilhados, há apenas uma instância de um Type por processo, o que significa que vários domínios de aplicativos compartilham a exata mesmo Type instância. Realizando um bloqueio um Type instância leva um bloqueio que afeta todo o processo, não apenas o AppDomain. Se um AppDomain leva um bloqueio em um Type objeto, em seguida, esse thread obtém interrompida abruptamente, não irá liberar o bloqueio. Em seguida, esse bloqueio pode causar outros domínios de aplicativo a deadlocks.

Uma boa maneira de levar os bloqueios em métodos estáticos envolve a adição de um objeto de sincronização interna estático no código. Isso poderia ser inicializado no construtor da classe caso haja algum, mas não podem ser inicializado como este:

private static Object s_InternalSyncObject;
private static Object InternalSyncObject 
{
    get 
    {
        if (s_InternalSyncObject == null) 
        {
            Object o = new Object();
            Interlocked.CompareExchange(
                ref s_InternalSyncObject, o, null);
        }
        return s_InternalSyncObject;
    }
}

E em seguida, ao colocar um bloqueio, use o InternalSyncObject a propriedade para obter um objeto para bloquear no. Você não precisará usar a propriedade se inicializou o objeto de sincronização interna no seu construtor de classe. O código de inicialização de bloqueio verificação dupla deve parecer com este exemplo:

public static MyClass SingletonProperty 
{
    get 
    {
        if (s_SingletonProperty == null) 
        {
            lock(InternalSyncObject) 
            {
                // Do not use lock(typeof(MyClass)) 
                if (s_SingletonProperty == null) 
                {
                    MyClass tmp = new MyClass(…);   
                    // Do all initialization before publishing
                    s_SingletonProperty = tmp;
                }
            }
        }
        return s_SingletonProperty;
    }
}

Uma observação sobre Lock (this)

É aceitável usar um bloqueio em um objeto individual que é acessível publicamente. No entanto, se o objeto for um objeto singleton que pode causar um subsistema inteiro para o deadlock, considere o uso o padrão de design acima também. Por exemplo, um bloqueio no SecurityManager objeto poderia causar um deadlock dentro do AppDomain fazer todo o AppDomain inutilizável. É recomendável não usar um bloqueio em um objeto acessível publicamente desse tipo. No entanto um bloqueio de uma matriz ou coleção individuais geralmente não deve representar um problema.

Regra de análise de código

Não utilizar bloqueios em tipos que podem ser usados em domínios de aplicativo ou não tem um forte senso de identidade. Do not call Enter on a Type, MethodInfo, PropertyInfo, String, ValueType, Thread, or any object that derives from MarshalByRefObject.

Remova o GC.Chamadas de KeepAlive

Uma quantidade significativa de código existente não usa KeepAlive quando ela deve ou usa-lo quando não for apropriado. Depois de converter em SafeHandle, classes não é necessário chamar KeepAlive, assumindo que não possuem um finalizador, mas dependem de SafeHandle para finalizar as alças do sistema operacional. Embora o custo de desempenho de retenção de uma chamada para KeepAlive pode ser insignificante, a percepção de que uma chamada para KeepAlive é necessário ou suficiente para resolver um problema que talvez não exista mais torna mais difícil manter o código de tempo de vida. No entanto, ao usar os COM interop CLR callable wrappers (RCWs), KeepAlive ainda é necessário pelo código.

Regra de análise de código

Remover KeepAlive.

Use o atributo de proteção de Host

O HostProtectionAttribute (HPA) fornece o uso das ações de segurança declarativos para determinar requisitos de proteção de host, permitindo que o host impedem que códigos mesmo totalmente confiável chamar determinados métodos que são inadequados para determinado host, como Exit ou Show para SQL Server.

O HPA afeta somente os aplicativos não gerenciados que hospedam o common language runtime e implementar proteção de host, como, por exemplo, SQL Server. Quando aplicado, os resultados da ação de segurança na criação de uma demanda de link baseiam nos recursos do host expõe a classe ou método. Se o código é executado em um aplicativo cliente ou em um servidor que não esteja protegido de host, o atributo "elimine"; não é detectado e, portanto, não é aplicada.

Observação importanteImportante

A finalidade deste atributo é aplicar as diretrizes de modelo programação específica de host, não o comportamento de segurança.Embora uma demanda de link é usada para verificar a conformidade com requisitos de modelo de programação de HostProtectionAttribute não é um segurança permissão.

Se o host não tem requisitos de modelo de programação, as demandas de link não ocorrem.

Este atributo identifica o seguinte:

  • Métodos ou classes que não cabem host programação do modelo, mas são contrário benigno.

  • Métodos ou classes que não se ajustam o modelo de programação do host e poderiam levar a desestabilizar o código do usuário do servidor gerenciado.

  • Métodos ou classes que não cabem host programação do modelo e podem levar a um destabilization do processo do servidor.

Observação

Se você estiver criando uma biblioteca de classe deve ser chamado por aplicativos que podem executar em um ambiente de host protegido, você deve aplicar esse atributo para membros que expõem HostProtectionResource categorias de recursos.A.Membros de biblioteca de classe do NET Framework com esse atributo causam somente o chamador imediato a ser verificado.O membro da biblioteca também deve causar uma verificação do seu chamador imediato da mesma maneira.

Por favor, para obter mais informações sobre HPA em HostProtectionAttribute.

Regra de análise de código

Para SQL Server, todos os métodos usados para introduzir a sincronização ou threading deve ser identificado com o HPA. Isso inclui métodos que compartilham o estado, são sincronizados ou gerenciar os processos externos. O HostProtectionResource de SQL Server de impacto que os valores são SharedState, Synchronization, e ExternalProcessMgmt. No entanto, qualquer método que expõe qualquer HostProtectionResource deve ser identificado por um HPA, não apenas aquelas que usam recursos que afetam o SQL.

Não bloquear indefinidamente em código não gerenciado

Bloqueio de código não gerenciado em vez de em código gerenciado pode causar um ataque de negação de serviço, porque o CLR não é capaz de anular o thread. Um thread bloqueado impede que o CLR descarregar o AppDomain, pelo menos sem realizando operações alguns extremamente inseguro. Bloqueio usando o Win32 o primitivo de sincronização é um exemplo claro de que algo que não podemos permitir. Bloqueio em uma chamada para ReadFile em um soquete deve ser evitado se possível — o ideal é que a API do Win32 deve fornecer um mecanismo para uma operação como esse tempo limite.

Qualquer método que chama nativo idealmente deve usar uma chamada Win32 com um tempo limite razoável, finito. Se o usuário tiver permissão para especificar o tempo limite, o usuário não deve poder para especificar um tempo limite de infinito sem alguma permissão de segurança específicas. Como diretriz, se um método bloqueará para mais de cerca de 10 segundos, você precisa estar usando uma versão que suporta os tempos limites ou precisar de suporte adicional do CLR.

Aqui estão alguns exemplos de API problemática. Pipes (anônimas e nomeadas) podem ser criados com um tempo limite; No entanto, código deve garantir que nunca chamadas CreateNamedPipe nem WaitNamedPipe com NMPWAIT_WAIT_FOREVER. Além disso, pode haver inesperado de bloqueio, mesmo se um tempo limite é especificado. Chamando WriteFile em um pipe anônimo será bloqueado até que todos os bytes são gravados, significando que se o buffer tem dados não lidos, a WriteFile chamada será bloqueado até que o leitor tenha liberado espaço no buffer do pipe. Soquetes sempre devem usar a API de honra um mecanismo de tempo limite.

Regra de análise de código

Bloqueando sem um tempo limite em código não gerenciado é um ataque de negação de serviço. Não executar a plataforma chamar chamadas para WaitForSingleObject, WaitForSingleObjectEx, WaitForMultipleObjects, MsgWaitForMultipleObjects, e MsgWaitForMultipleObjectsEx. Não use NMPWAIT_WAIT_FOREVER.

Identifica quaisquer recursos dependentes de STA.

Identifica qualquer código que usa COM segmentação única (STAs). STAs estão desabilitados no processo de SQL Server. Os recursos que dependem de CoInitialize, como desempenho contadores ou a área de transferência deve estar desativado em SQL Server.

Garantir finalizadores estejam livres de problemas de sincronização

Vários segmentos do finalizador possam existir nas futuras versões do.NET Framework, que significa que os finalizadores para instâncias diferentes do mesmo tipo são executados simultaneamente. Não é necessário ser completamente thread-safe; o coletor de lixo garante que apenas um thread executará o finalizador para uma instância do objeto fornecido. No entanto, os finalizadores devem ser codificados para evitar deadlocks e condições de corrida quando executados simultaneamente em várias instâncias de objeto diferente. Ao usar qualquer estado externo, como, por exemplo, gravar em um arquivo de log em um finalizador, threading problemas deve ser manipulada. Não confie na finalização para fornecer a segurança do thread. Não use o armazenamento local de segmento, gerenciado ou nativo, para armazenar o estado no thread do finalizador.

Regra de análise de código

Os finalizadores devem estar livres de problemas de sincronização. Não use um estado mutável estático em um finalizador.

Evite se possível de memória não gerenciada

Memória não gerenciada pode vazar, assim como um identificador de sistema operacional. Se possível, tente usar a memória na pilha usando o stackalloc (referência de TRANSLATION FROM VPE FOR CSHARP) ou um objeto gerenciado fixado, como o Instrução fixa (referência C#) ou GCHandle usando um byte []. O GC eventualmente limpa esses ativo. \ No entanto, se você deve alocar memória não gerenciada, considere usar uma classe que deriva de SafeHandle para encapsular a alocação de memória.

Observe que há pelo menos um caso onde SafeHandle não é adequada. Para chamadas de método COM que alocar ou liberem memória, é comum para uma DLL alocar a memória através de CoTaskMemAlloc , em seguida, outra DLL libera a memória com CoTaskMemFree. Usando SafeHandle nestes locais seria inadequado, pois ele tentará vincular a vida útil da memória não gerenciada para a vida útil do SafeHandle em vez de permitir a outro controle DLL o tempo de vida da memória.

Revise todos os usos de Catch(Exception)

Catch blocos que interceptar todas as exceções de em vez de uma exceção específica agora irá capturar exceções assíncronas. Examine cada bloco de catch(Exception), procurando nenhum código de liberando ou devolução de recursos importantes que devem ser ignorado, bem como um comportamento incorreto potencialmente dentro do próprio bloco de catch para manipular um ThreadAbortException, StackOverflowException, ou OutOfMemoryException. Observe que é possível que esse código pode fazer ou fazendo algumas suposições que ele pode ver apenas certas exceções ou que sempre que ocorrer uma exceção, ele falha para exatamente uma razão específica. Essas suposições talvez precise ser atualizado para incluir ThreadAbortException.

Considere alterar tudo coloca que interceptar todas as exceções a captura de um tipo específico de exceção que você espera que serão lançadas, como um FormatException de seqüência de caracteres de formatação métodos. Isso impede que o bloco catch executados em exceções inesperadas e ajudará a garantir que o código não oculta os bugs por capturar exceções inesperadas. Como regra geral nunca manipular uma exceção no código da biblioteca (código requer que você capturar uma exceção pode indicar uma falha de design no código que você está chamando). Em alguns casos você poderá capturar uma exceção e lançar um tipo de exceção diferente para fornecer mais dados. Use as exceções aninhadas nesse caso, armazenando a causa real da falha no InnerException a propriedade da nova exceção.

Regra de análise de código

Revise todos os blocos catch no código gerenciado que catch todos os objetos ou interceptar todas as exceções. Em C#, isso significa a sinalização de ambos catch {} e catch(Exception) {}. Considere o tipo de exceção muito específicas ou revisar o código para garantir que não agir de forma incorreta se ele o alcança um tipo de exceção inesperada.

Não pressuponha que um segmento gerenciado é um Thread do Win32 – É uma fibra

Usando gerenciado segmento local de armazenamento funcionar, mas não pode usar o armazenamento local de thread não gerenciado ou assumir que o código será executado novamente no thread do sistema operacional atual. Não altere as configurações como localidade do thread. Não chame InitializeCriticalSection ou CreateMutex por meio da plataforma invoke porque elas exigem que entra em um bloqueio de thread do sistema operacional também sair do bloqueio. Desde que esse não será o caso ao usar fibras, exclusões mútuas e seções críticas do Win32 não podem ser usadas em SQL diretamente. Observe que o gerenciado Mutex classe não manipular essas preocupações de afinidade de thread.

Você pode usar com segurança a maioria do estado em um gerenciado Thread objeto, incluindo o armazenamento local de thread gerenciado e o thread atual UI culture. Você também pode usar o ThreadStaticAttribute, que torna o valor de uma variável estática existente acessível somente pelo segmento atual gerenciado (Este é outra maneira de fazer o armazenamento local de fibra no CLR). Para razões de modelo de programação, não é possível alterar a cultura atual de um thread quando executado em SQL.

Regra de análise de código

SQL Server é executado no modo de fibra; não use o armazenamento local de segmento. Evitar a plataforma chamar chamadas para TlsAlloc, TlsFree, TlsGetValue, e TlsSetValue.

Permitir que a representação da alça de SQL Server

Como a representação opera em nível de thread e SQL pode executar no modo de fibra, código gerenciado não deve representar usuários e não deve chamar RevertToSelf.

Regra de análise de código

Permitem que SQL Server a lidar com a representação. Do not use RevertToSelf, ImpersonateAnonymousToken, DdeImpersonateClient, ImpersonateDdeClientWindow, ImpersonateLoggedOnUser, ImpersonateNamedPipeClient, ImpersonateSelf, RpcImpersonateClient, RpcRevertToSelf, RpcRevertToSelfEx, or SetThreadToken.

Não chame Thread::Suspend

A capacidade de suspender um segmento pode aparecer em uma operação simple, mas ela pode causar deadlocks. Se um thread, mantendo que um bloqueio obtém suspenso por um segundo thread e, em seguida, o segundo segmento tenta fazer o mesmo bloqueio, ocorre um deadlock. Suspendpodem interferir com a segurança, carregamento de classe, remoting e reflexão no momento.

Regra de análise de código

Não chame Suspend. Considere o uso de uma sincronização real primitivo em vez disso, como um Semaphore ou ManualResetEvent .

Proteger as operações críticas com contratos de confiabilidade e de regiões de execução restrita

Ao executar uma operação complexa que atualiza o status compartilhado ou que precisa para determinista seja totalmente bem-sucedida ou totalmente falhar, certifique-se de que ele está protegido por uma região de execução restrita (CER). Isso garante que o código é executado em todos os casos, até mesmo uma anulação de thread abrupta ou um abrupto AppDomain unload.

Uma CER está em um determinado try/finally bloco imediatamente precedido por uma chamada para PrepareConstrainedRegions.

Fazendo assim instrui o compilador just-in-time para preparar a todo o código no bloco finally antes de executar o try bloco. Isso garante que o código a finalmente bloco é criado e será executado em todos os casos. Não é incomum em uma CER ter um vazio try bloco. Usar uma CER protege contra anulações de thread assíncronas e exceções de memória insuficiente. Consulte ExecuteCodeWithGuaranteedCleanup para um formulário de uma CER que manipula Além disso estouros de pilha para código excessivamente profundo.

Consulte também

Referência

System.Runtime.ConstrainedExecution

Conceitos

Atributos de proteção de Host e de programação de SQL Server