Partilhar via


Práticas recomendadas para o carregamento de Assembly

Este artigo discute as maneiras de evitar problemas de identidade de tipo que pode levar a InvalidCastException, MissingMethodExceptione outros erros. O artigo aborda as seguintes recomendações:

  • Compreender as vantagens e desvantagens dos contextos de carga

  • Evitar a ligação de nomes parciais de assembly

  • Evitar o carregamento de um assembly em vários contextos

  • Evitar o carregamento de várias versões de um assembly no mesmo contexto

  • Considere a possibilidade de alternar para o contexto de carregamento padrão

A primeira recomendação, entender as vantagens e desvantagens dos contextos de carga, fornece informações de plano de fundo para as recomendações, porque todos eles dependem de dados de Conhecimento dos contextos de carga.

Compreender as vantagens e desvantagens dos contextos de carga

Em um domínio de aplicativo, assemblies podem ser carregados em um dos três contextos ou pode ser carregados sem contexto:

  • O contexto de carregamento padrão contém os assemblies encontrados por probing global assembly cache, o armazenamento de assembly do host se o tempo de execução está hospedado (por exemplo, em SQL Server) e o ApplicationBase e PrivateBinPath do domínio de aplicativo. A maioria das sobrecargas da Load método carregar assemblies no contexto.

  • O contexto de carga de rede contém os assemblies são carregados a partir de locais que não são pesquisados pelo carregador do. Por exemplo, add-ins pode ser instalados em um diretório que não está sob o caminho do aplicativo. Assembly.LoadFrom, AppDomain.CreateInstanceFrom, e AppDomain.ExecuteAssembly são exemplos de métodos que carregar pelo caminho.

  • O contexto somente de reflexão contém os assemblies carregados com o ReflectionOnlyLoad e ReflectionOnlyLoadFrom métodos. O código neste contexto não pode ser executado para que ela não será discutida aqui. Para obter mais informações, consulte Como: Carregar Assemblies no contexto somente de reflexão.

  • Se você gerou um assembly dinâmico transitório usando reflexão emitir, o assembly não está em qualquer contexto. Além disso, a maioria dos assemblies que são carregados por meio de LoadFile método são carregados sem contexto, e que são carregados a partir de matrizes de bytes de assemblies são carregados sem contexto, a menos que sua identidade (depois que a diretiva é aplicada) estabelece que estão no cache global de assemblies.

Os contextos de execução tem vantagens e desvantagens, como discutido nas seções a seguir.

Contexto de carregamento padrão

Quando os assemblies são carregados no contexto de carregamento padrão, suas dependências são carregadas automaticamente. Dependências são carregadas no contexto de carregamento padrão encontram-se automaticamente para assemblies no contexto de carregamento padrão ou o contexto de carga de rede. Carregamento de identidade assembly aumenta a estabilidade de aplicativos, garantindo que as versões desconhecidas de assemblies não são usadas (consulte a Evitar ligação em nomes parciais de Assembly seção).

Usar o contexto de carregamento padrão possui as seguintes desvantagens:

  • Não há dependências que são carregadas em outros contextos.

  • Você não pode carregar assemblies de locais fora do caminho de sondagem para o contexto de carregamento padrão.

Contexto de carga de rede

O contexto de carga de rede permite que você carregar um assembly de um caminho que não está sob o caminho do aplicativo e, portanto, não está incluído na investigação. Ele permite que dependências ser localizado e carregado a partir do caminho, porque as informações de caminho são mantidas pelo contexto. Além disso, os assemblies neste contexto podem usar as dependências que são carregadas no contexto de carregamento padrão.

Carregar assemblies usando o Assembly.LoadFrom método ou um dos outros métodos que carregam pelo caminho, tem as seguintes desvantagens:

  • Se um assembly com a mesma identidade já está carregado, LoadFrom retorna o assembly carregado, mesmo se um caminho diferente foi especificado.

  • Se um conjunto é carregado com LoadFrom, e posteriormente um assembly no contexto de carregamento padrão tenta carregar o assembly de mesmo nome de exibição falha de tentativa de carregar. Isso pode ocorrer quando um assembly é desserializado.

  • Se um conjunto é carregado com LoadFrom, e o caminho de probing inclui um assembly com a mesma identidade, mas em um local diferente, um InvalidCastException, MissingMethodException, ou outros comportamentos inesperados podem ocorrer.

  • LoadFromdemandas de FileIOPermissionAccess.Read e FileIOPermissionAccess.PathDiscovery, ou WebPermission, em que o caminho especificado

  • Se houver uma imagem nativa para o assembly, não é usado.

  • O assembly não pode ser carregado como domínio neutro.

  • No.NET Framework versões 1.0 e 1.1, a diretiva não é aplicada.

Nenhum contexto

Carregar sem contexto é a única opção para transitórios assemblies que são gerados com reflexão emitir. O carregamento sem contexto é a única maneira de carregar vários assemblies que têm a mesma identidade em um domínio do aplicativo. O custo de sondagem é evitado.

Assemblies são carregados a partir de matrizes de bytes que são carregados sem contexto, a menos que a identidade do assembly, é estabelecida quando a diretiva é aplicada, coincide com a identidade de um assembly no cache de assembly global; Nesse caso, o assembly foi carregado no cache global de assemblies.

Carregar assemblies sem contexto possui as seguintes desvantagens:

  • Outros assemblies não é possível vincular a assemblies são carregados sem contexto, a menos que você lida com o AppDomain.AssemblyResolve de evento.

  • Dependências não são carregadas automaticamente. Pré-carregar sem contexto, pré-carregar no contexto de carregamento padrão ou carregá-los pelo tratamento de AppDomain.AssemblyResolve de evento.

  • Carregar vários assemblies com a mesma identidade sem contexto pode causar problemas de identidade de tipo semelhantes para aqueles causados por carregamento de módulos (assemblies) com a mesma identidade em vários contextos. Consulte evitar o carregamento de um Assembly em vários contextos.

  • Se houver uma imagem nativa para o assembly, não é usado.

  • O assembly não pode ser carregado como domínio neutro.

  • No.NET Framework versões 1.0 e 1.1, a diretiva não é aplicada.

Evitar a vinculação de nomes parciais de Assembly

Vinculação de nome parcial ocorre quando você especifica apenas parte do nome de exibição do assembly (FullName) quando você carrega um assembly. Por exemplo, você poderia chamar o Assembly.Load método com somente o nome simple do assembly, omitindo a versão, cultura e token de chave pública. Ou você pode chamar o Assembly.LoadWithPartialName método, que primeiro chama o Assembly.Load método e, se isso falhar localizar o assembly, procura o cache global de assemblies e carrega a versão mais recente do assembly.

Ligação de nome parcial pode causar vários problemas, incluindo o seguinte:

  • O Assembly.LoadWithPartialName método pode carregar um assembly diferente com o mesmo nome simples. Por exemplo, dois aplicativos podem instalar os dois assemblies completamente diferentes que têm o nome simples GraphicsLibrary na cache global de assemblies.

  • O assembly que é na verdade carregado pode não ser compatível. Por exemplo, a não especificar a versão pode resultar em muito posterior à versão que do programa foi originalmente escrito para usar o carregamento. Alterações na versão mais recente podem causar erros em seu aplicativo.

  • O assembly que é na verdade carregado pode não ser compatível com o encaminhamento. Por exemplo, pode ter criado e testado seu aplicativo com a versão mais recente de um assembly, mas a ligação parcial pode carregar uma versão muito anterior que não possui recursos de que seu aplicativo usa.

  • Instalar novos aplicativos pode interromper os aplicativos existentes. Um aplicativo que usa o LoadWithPartialName método pode ser quebrado por instalar uma versão mais recente, incompatível de um assembly compartilhado.

  • Carregamento de dependência inesperados pode ocorrer. Ele que carregar dois assemblys que compartilham uma dependência, carregá-los com ligação parcial pode resultar em um assembly usando um componente que não foi criado ou testado com.

Por causa dos problemas podem causar, o LoadWithPartialName método foi marcado como obsoleto. Recomendamos que você use o Assembly.Load método em vez disso e especifique o conjunto completo de exibir nomes. Consulte entender as vantagens e desvantagens dos contextos de carga e considere trocar para o contexto de carregamento padrão.

Se você quiser usar o LoadWithPartialName método porque torna fácil, de carregamento de assembly considere que seu aplicativo falhar com uma mensagem de erro que identifica o assembly ausente provavelmente proporcionar uma melhor experiência de usuário que automaticamente usando uma versão desconhecida do assembly, que pode causar imprevisíveis segurança e comportamento orifícios.

Evitar o carregamento de um Assembly em vários contextos

Carregar um assembly em vários contextos pode causar problemas de identidade de tipo. Se o mesmo tipo é carregado a partir do mesmo assembly em dois contextos diferentes, é como se os dois tipos diferentes com o mesmo nome tinham sido carregados. Um InvalidCastException é lançada se você tentar converter um tipo para outro, com a mensagem confusa que digite MyType não pode ser convertida para o tipo MyType.

Por exemplo, suponha que o ICommunicate interface é declarado em um assembly chamado Utility, que é referenciado por seu programa e também por outros assemblies que carrega seu programa. Esses outros assemblies contém tipos que implementam o ICommunicate interface, permitindo que o seu programa de usá-los.

Agora, considere o que acontece quando o programa é executado. Assemblies são referenciados por seu programa são carregados no contexto de carregamento padrão. Se você carregar um assembly de destino por sua identidade, usando o Load método, ele será no contexto de carregamento padrão, e então será dependências. Seu programa e o assembly de destino usará o mesmo Utility assembly.

No entanto, suponha que você carrega o assembly de destino por seu caminho de arquivo, usando o LoadFile método. O assembly foi carregado sem qualquer contexto, portanto, suas dependências não são carregadas automaticamente. Você pode ter um manipulador para o AppDomain.AssemblyResolve evento para fornecer a dependência e ele pode carregar o Utility assembly com nenhum contexto usando o LoadFile método. Agora quando você cria uma instância de um tipo que está contido no assembly de destino e tente atribuí-la a uma variável do tipo ICommunicate, um InvalidCastException é lançada porque o runtime considera o ICommunicate interfaces em duas cópias da Utility assembly para ser tipos diferentes.

Há muitos outros cenários em que um assembly pode ser carregado em vários contextos. A melhor abordagem é evitar conflitos de realocação de assembly de destino no caminho do aplicativo e usando o Load método with the full exibir nome. O assembly, em seguida, é carregado no contexto de carregamento padrão e os dois assemblies usarem a mesma Utility assembly.

Se o assembly de destino deve permanecer fora do caminho do aplicativo, você pode usar o LoadFrom método carregá-lo na carga de contexto. Se o assembly de destino foi compilado com uma referência ao seu aplicativo Utility assembly, ele usará o Utility assembly que seu aplicativo carregou no contexto de carga padrão. Observe que podem ocorrer problemas se o assembly de destino tem uma dependência em uma cópia da Utility assembly localizado fora do caminho de aplicativo. Se esse conjunto é carregado no contexto de carga de rede antes da cargas de aplicativos de Utility assembly, carga de irá falhar. seu aplicativo

O Considere alternando para o contexto de carregamento padrão seção discute as alternativas ao uso de cargas de caminho do arquivo como LoadFile e LoadFrom.

Evitar o carregamento de várias versões de um Assembly no mesmo contexto

Carregamento de várias versões de um assembly em um contexto de carregamento pode causar problemas de identidade de tipo. Se o mesmo tipo é carregado a partir de duas versões do mesmo assembly, é como se os dois tipos diferentes com o mesmo nome tinham sido carregados. Um InvalidCastException é lançada se você tentar converter um tipo para outro, com a mensagem confusa que digite MyType não pode ser convertida para o tipo MyType.

Por exemplo, o seu programa pode carregar uma versão do Utility assembly diretamente e posteriormente pode carregar o outro conjunto que carrega uma versão diferente da Utility assembly. Ou um erro de codificação pode causar dois caminhos de código diferente em seu aplicativo para carregar diferentes versões de um assembly.

No contexto de carregamento padrão, esse problema pode ocorrer quando você usa o Assembly.Load método e especificar os nomes para exibição completa do assembly que incluem números de versão diferente. Para os assemblies são carregados sem contexto, o problema pode ser causado por meio de Assembly.LoadFile método para carregar o mesmo assembly de caminhos diferentes. O runtime considera dois assemblies são carregados a partir de diferentes caminhos de ser assemblies diferentes, mesmo que suas identidades são os mesmos.

Além de para problemas de identidade de tipo, várias versões de um assembly podem causar uma MissingMethodException se um tipo que é carregado a partir de uma versão do assembly é passado para o código que espera que esse tipo de uma versão diferente. Por exemplo, o código poderia esperar de um método que foi adicionado para a versão mais recente.

Mais erros sutis podem ocorrer se o comportamento do tipo alterado entre versões. Por exemplo, um método pode lançar uma exceção inesperada ou retornar um valor inesperado.

Examinar cuidadosamente o código para garantir que apenas uma versão de um assembly é carregado. Você pode usar o AppDomain.GetAssemblies método para determinar quais assemblies são carregados em qualquer tempo determinado.

Considere a possibilidade de alternar para o contexto de carregamento padrão

Examine os padrões de implantação e o carregamento de assembly do aplicativo. Você pode eliminar os assemblies são carregados a partir de matrizes de bytes? Você pode mover assemblies no caminho de probing? Se encontram os assemblies no cache global de assemblies ou no domínio do aplicativo da investigação caminho (ou seja, sua ApplicationBase e PrivateBinPath), você pode carregar o assembly por identidade.

Se não for possível colocar todos os seus assemblies no caminho de probing, considere alternativas como usando o.NET Framework add-in do modelo, colocando os assemblies no cache global de assemblies ou criação de domínios de aplicativo.

Considere o uso do.Modelo de suplemento do NET Framework

Se você estiver usando o contexto de carga para implementar o add-ins, que normalmente não estão instalados no uso do aplicativo base, o.NET Framework add-in do modelo. Esse modelo fornece isolamento no nível processo ou de domínio do aplicativo, sem a necessidade de gerenciar domínios de aplicativo por conta própria. Para obter informações sobre o modelo de suplemento, consulte Add-ins e extensibilidade.

Considere o uso de Cache Global de assemblies

Assemblies de lugar no cache global de assemblies para obter o benefício de um caminho de assembly compartilhado que está fora do aplicativo base, sem perder as vantagens de contexto de carregamento padrão ou assumir as desvantagens dos outros contextos.

Considere o uso de domínios de aplicativo

Se você determinar que alguns de seus assemblies não podem ser implantado no caminho de sondagem do aplicativo, considere a criação de um novo domínio de aplicativo para esses assemblies. Usar um AppDomainSetup para criar um novo domínio de aplicativo e usar o AppDomainSetup.ApplicationBase propriedade para especificar o caminho que contém os assemblies que você deseja carregar. Se você tiver vários diretórios de teste, você pode definir a ApplicationBase para um diretório raiz e usar o AppDomainSetup.PrivateBinPath propriedade para identificar os subdiretórios para teste. Como alternativa, você pode criar vários domínios de aplicativo e definir o ApplicationBase de cada domínio de aplicativo para o caminho apropriado para assemblies.

Observe que você pode usar o Assembly.LoadFrom método para carregar esses módulos (assemblies). Porque agora estão no caminho de probing, será carregados no contexto de carregamento padrão, em vez do contexto de carga. No entanto, recomendamos que você alterne para o Assembly.Load método e a fonte completa de nomes de exibição de assembly para garantir que as versões corretas são sempre usadas.

Consulte também

Referência

Assembly.Load

Assembly.LoadFrom

Assembly.LoadFile

AppDomain.AssemblyResolve

Conceitos

Add-ins e extensibilidade