Como o tempo de execução localiza assemblies
Nota
Este artigo é específico do .NET Framework. Ele não se aplica a implementações mais recentes do .NET, incluindo o .NET 6 e versões posteriores.
Para implantar com êxito seu aplicativo .NET Framework, você deve entender como o common language runtime localiza e se liga aos assemblies que compõem seu aplicativo. Por padrão, o tempo de execução tenta se vincular à versão exata de um assembly com o qual o aplicativo foi criado. Esse comportamento padrão pode ser substituído pelas definições do arquivo de configuração.
O common language runtime executa várias etapas ao tentar localizar um assembly e resolver uma referência de assembly. Cada etapa é explicada nas seções a seguir. O termo sondagem é frequentemente usado ao descrever como o tempo de execução localiza assemblies; refere-se ao conjunto de heurísticas usadas para localizar a montagem com base em seu nome e cultura.
Nota
Você pode exibir informações de associação no arquivo de log usando o Assembly Binding Log Viewer (Fuslogvw.exe), que está incluído no SDK do Windows.
Iniciando a ligação
O processo de localização e vinculação a um assembly começa quando o tempo de execução tenta resolver uma referência a outro assembly. Esta referência pode ser estática ou dinâmica. O compilador registra referências estáticas nos metadados do manifesto do assembly no momento da compilação. Referências dinâmicas são construídas em tempo real como resultado da chamada de vários métodos, como Assembly.Load.
A maneira preferida de fazer referência a um assembly é usar uma referência completa, incluindo o nome do assembly, versão, cultura e token de chave pública (se existir). O tempo de execução usa essas informações para localizar o assembly, seguindo as etapas descritas posteriormente nesta seção. O tempo de execução usa o mesmo processo de resolução, independentemente de a referência ser para um assembly estático ou dinâmico.
Você também pode fazer uma referência dinâmica a um assembly fornecendo ao método de chamada apenas informações parciais sobre o assembly, como especificar apenas o nome do assembly. Nesse caso, apenas o diretório do aplicativo é pesquisado para o assembly e nenhuma outra verificação ocorre. Você faz uma referência parcial usando qualquer um dos vários métodos para carregar assemblies, como Assembly.Load ou AppDomain.Load.
Finalmente, você pode fazer uma referência dinâmica usando um método como Assembly.Load e fornecer apenas informações parciais, em seguida, qualificar a referência usando o <elemento qualifyAssembly> no arquivo de configuração do aplicativo. Esse elemento permite que você forneça as informações de referência completas (nome, versão, cultura e, se aplicável, o token de chave pública) no arquivo de configuração do aplicativo em vez de no código. Você usaria essa técnica se quisesse qualificar totalmente uma referência a um assembly fora do diretório do aplicativo ou se quisesse fazer referência a um assembly no cache de assembly global, mas quisesse a conveniência de especificar a referência completa no arquivo de configuração em vez de no código.
Nota
Esse tipo de referência parcial não deve ser usado com assemblies que são compartilhados entre vários aplicativos. Como as definições de configuração são aplicadas por aplicativo e não por assembly, um assembly compartilhado usando esse tipo de referência parcial exigiria que cada aplicativo usando o assembly compartilhado tivesse as informações de qualificação em seu arquivo de configuração.
O tempo de execução usa as seguintes etapas para resolver uma referência de assembly:
Determina a versão correta do assembly examinando os arquivos de configuração aplicáveis, incluindo o arquivo de configuração do aplicativo, o arquivo de política do editor e o arquivo de configuração da máquina. Se o arquivo de configuração estiver localizado em uma máquina remota, o tempo de execução deverá localizar e baixar o arquivo de configuração do aplicativo primeiro.
Verifica se o nome do assembly foi vinculado antes e, em caso afirmativo, usa o assembly carregado anteriormente. Se uma solicitação anterior para carregar o assembly falhar, a solicitação falhará imediatamente sem tentar carregar o assembly.
Nota
O cache de falhas de vinculação de assembly é novo no .NET Framework versão 2.0.
Verifica o cache de assembly global. Se o assembly for encontrado lá, o tempo de execução usará esse assembly.
Testes para o conjunto usando as seguintes etapas:
Se a configuração e a política do editor não afetarem a referência original e se a solicitação de associação tiver sido criada usando o Assembly.LoadFrom método, o tempo de execução verificará se há dicas de local.
Se uma base de código for encontrada nos arquivos de configuração, o tempo de execução verificará apenas esse local. Se esse teste falhar, o tempo de execução determinará que a solicitação de associação falhou e nenhuma outra sondagem ocorre.
Sondas para a montagem usando a heurística descrita na seção de sondagem. Se o assembly não for encontrado após a sondagem, o tempo de execução solicitará que o Windows Installer forneça o assembly. Isso funciona como um recurso de instalação sob demanda.
Nota
Não há verificação de versão para assemblies sem nomes fortes, nem o tempo de execução verifica no cache de assembly global para assemblies sem nomes fortes.
Etapa 1: Examinando os arquivos de configuração
O comportamento de vinculação de assembly pode ser configurado em diferentes níveis com base em três arquivos XML:
Arquivo de configuração do aplicativo.
Arquivo de política do editor.
Arquivo de configuração da máquina.
Esses arquivos seguem a mesma sintaxe e fornecem informações como redirecionamentos de ligação, o local do código e modos de ligação para assemblies específicos. Cada arquivo de configuração pode conter um <elemento assemblyBinding> que redireciona o processo de vinculação. Os elementos filho do elemento assemblyBinding> incluem o< elemento dependentAssembly>.< Os filhos do elemento dependentAssembly> incluem o <elemento assemblyIdentity>, o <elemento bindingRedirect> e o< elemento codeBase.><
Nota
As informações de configuração podem ser encontradas nos três arquivos de configuração; Nem todos os elementos são válidos em todos os arquivos de configuração. Por exemplo, o modo de vinculação e as informações de caminho privado só podem estar no arquivo de configuração do aplicativo. Para obter uma lista completa das informações contidas em cada arquivo, consulte Configurando aplicativos usando arquivos de configuração.
Application Configuration File
Primeiro, o common language runtime verifica o arquivo de configuração do aplicativo em busca de informações que substituam as informações de versão armazenadas no manifesto do assembly de chamada. O arquivo de configuração do aplicativo pode ser implantado com um aplicativo, mas não é necessário para a execução do aplicativo. Normalmente, a recuperação desse arquivo é quase instantânea, mas em situações em que a base do aplicativo está em um computador remoto, como em um cenário baseado na Web, o arquivo de configuração deve ser baixado.
Para executáveis cliente, o arquivo de configuração do aplicativo reside no mesmo diretório que o executável do aplicativo e tem o mesmo nome base que o executável com uma extensão .config. Por exemplo, o arquivo de configuração para C:\Program Files\Myapp\Myapp.exe é C:\Program Files\Myapp\Myapp.exe.config. Em um cenário baseado em navegador, o arquivo HTML deve usar o <elemento link> para apontar explicitamente para o arquivo de configuração.
O código a seguir fornece um exemplo simples de um arquivo de configuração do aplicativo. Este exemplo adiciona um TextWriterTraceListener à coleção para habilitar a Listeners gravação de informações de depuração em um arquivo.
<configuration>
<system.diagnostics>
<trace useGlobalLock="false" autoflush="true" indentsize="0">
<listeners>
<add name="myListener" type="System.Diagnostics.TextWriterTraceListener, system version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" initializeData="c:\myListener.log" />
</listeners>
</trace>
</system.diagnostics>
</configuration>
Arquivo de política do Publisher
Em segundo lugar, o tempo de execução examina o arquivo de política do editor, se existir. Os arquivos de política do Publisher são distribuídos por um editor de componentes como uma correção ou atualização para um componente compartilhado. Esses arquivos contêm informações de compatibilidade emitidas pelo editor do componente compartilhado que direciona uma referência de assembly para uma nova versão. Ao contrário dos arquivos de configuração de aplicativos e máquinas, os arquivos de política do editor estão contidos em seu próprio assembly que deve ser instalado no cache de assembly global.
Segue-se um exemplo de um ficheiro de configuração da Política do Publisher:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="asm6" publicKeyToken="c0305c36380ba429" />
<bindingRedirect oldVersion="3.0.0.0" newVersion="2.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Para criar um assembly, você pode usar a ferramenta Al.exe (Assembly Linker) com um comando como o seguinte:
Al.exe /link:asm6.exe.config /out:policy.3.0.asm6.dll /keyfile: compatkey.dat /v:3.0.0.0
compatkey.dat
é um arquivo de chave de nome forte. Este comando cria um assembly de nome forte que você pode colocar no cache de assembly global.
Nota
A política do Publisher afeta todos os aplicativos que usam um componente compartilhado.
O arquivo de configuração de política do editor substitui as informações de versão provenientes do aplicativo (ou seja, do manifesto do assembly ou do arquivo de configuração do aplicativo). Se não houver nenhuma instrução no arquivo de configuração do aplicativo para redirecionar a versão especificada no manifesto do assembly, o arquivo de política do editor substituirá a versão especificada no manifesto do assembly. No entanto, se houver uma instrução de redirecionamento no arquivo de configuração do aplicativo, a política do editor substituirá essa versão em vez da especificada no manifesto.
Um arquivo de política do editor é usado quando um componente compartilhado é atualizado e a nova versão do componente compartilhado deve ser coletada por todos os aplicativos que usam esse componente. As configurações no arquivo de política do editor substituem as configurações no arquivo de configuração do aplicativo, a menos que o arquivo de configuração do aplicativo imponha o modo de segurança.
Modo de Segurança
Os arquivos de política do Publisher geralmente são instalados explicitamente como parte de um service pack ou atualização de programa. Se houver algum problema com o componente compartilhado atualizado, você poderá ignorar as substituições no arquivo de política do editor usando o modo de segurança. O modo de segurança é determinado pelo <elemento publisherPolicy apply="yes|no"/>, localizado apenas no arquivo de configuração do aplicativo. Ele especifica se as informações de configuração da política do editor devem ser removidas do processo de vinculação.
O modo de segurança pode ser definido para todo o aplicativo ou para assemblies selecionados. Ou seja, você pode desativar a política para todos os assemblies que compõem o aplicativo ou ativá-la para alguns assemblies, mas não para outros. Para aplicar seletivamente a política de editor a assemblies que compõem um aplicativo, defina publisherPolicy apply=no/> e especifique quais assemblies você deseja que sejam afetados usando o< elemento dependentAssembly>.< Para aplicar a política de editor a todos os assemblies que compõem o aplicativo, defina <publisherPolicy apply=no/> sem elementos de assembly dependentes. Para obter mais informações sobre configuração, consulte Configurando aplicativos usando arquivos de configuração.
Arquivo de configuração da máquina
Em terceiro lugar, o tempo de execução examina o arquivo de configuração da máquina. Esse arquivo, chamado Machine.config, reside no computador local no subdiretório Config do diretório raiz onde o tempo de execução está instalado. Esse arquivo pode ser usado por administradores para especificar restrições de vinculação de assembly que são locais para esse computador. As configurações no arquivo de configuração da máquina têm precedência sobre todas as outras definições de configuração; No entanto, isso não significa que todas as definições de configuração devam ser colocadas neste arquivo. A versão determinada pelo arquivo de política do administrador é final e não pode ser substituída. As substituições especificadas no arquivo Machine.config afetam todos os aplicativos. Para obter mais informações sobre arquivos de configuração, consulte Configurando aplicativos usando arquivos de configuração.
Etapa 2: Verificando assemblies referenciados anteriormente
Se o assembly solicitado também tiver sido solicitado em chamadas anteriores, o common language runtime usará o assembly que já está carregado. Isso pode ter ramificações ao nomear assemblies que compõem um aplicativo. Para obter mais informações sobre como nomear assemblies, consulte Nomes de assembly.
Se uma solicitação anterior para o assembly falhar, as solicitações subsequentes para o assembly falharão imediatamente sem tentar carregar o assembly. A partir do .NET Framework versão 2.0, as falhas de vinculação de assembly são armazenadas em cache e as informações armazenadas em cache são usadas para determinar se o assembly deve ser tentado.
Nota
Para reverter para o comportamento das versões 1.0 e 1.1 do .NET Framework, que não armazenaram falhas de vinculação em cache, inclua o <elemento disableCachingBindingFailures no arquivo de> configuração.
Etapa 3: Verificando o cache de assembly global
Para assemblies de nome forte, o processo de vinculação continua examinando o cache de assembly global. O cache de assembly global armazena assemblies que podem ser usados por vários aplicativos em um computador. Todos os assemblies no cache de assembly global devem ter nomes fortes.
Etapa 4: Localizando o assembly através de bases de código ou sondagem
Depois que a versão correta do assembly tiver sido determinada usando as informações na referência do assembly de chamada e nos arquivos de configuração, e depois que ele tiver verificado no cache global do assembly (somente para assemblies de nome forte), o common language runtime tentará localizar o assembly. O processo de localização de um assembly envolve as seguintes etapas:
Se um <elemento codeBase> for encontrado no arquivo de configuração do aplicativo, o tempo de execução verificará o local especificado. Se uma correspondência for encontrada, esse assembly será usado e nenhuma sondagem ocorrerá. Se o assembly não for encontrado lá, a solicitação de vinculação falhará.
Em seguida, o tempo de execução investiga o assembly referenciado usando as regras especificadas posteriormente nesta seção.
Nota
Se você tiver várias versões de um assembly em um diretório e quiser fazer referência a uma versão específica desse assembly, deverá usar o elemento codeBase> em vez do privatePath
atributo do elemento de< sondagem>.< Se você usar o <elemento probing> , o tempo de execução para de sondar na primeira vez que encontrar um assembly que corresponda ao nome de assembly simples referenciado, seja ele uma correspondência correta ou não. Se for uma correspondência correta, esse assembly é usado. Se não for uma correspondência correta, a sondagem para e a ligação falha.
Localizando o assembly através de bases de código
As informações da base de código podem ser fornecidas usando um <elemento codeBase> em um arquivo de configuração. Essa base de código é sempre verificada antes que o tempo de execução tente investigar o assembly referenciado. Se um arquivo de política do editor contendo o redirecionamento da versão final também contiver um <elemento codeBase>, esse< elemento codeBase> será o usado. Por exemplo, se o arquivo de configuração do aplicativo especificar um <elemento codeBase> e um arquivo de política do editor que está substituindo as informações do aplicativo também especificar um< elemento codeBase>, o <elemento codeBase> no arquivo de política do editor será usado.
Se nenhuma correspondência for encontrada no local especificado pelo <elemento codeBase> , a solicitação de associação falhará e nenhuma outra etapa será executada. Se o tempo de execução determinar que um assembly corresponde aos critérios do assembly chamador, ele usará esse assembly. Quando o arquivo especificado pelo elemento codeBase> fornecido <é carregado, o tempo de execução verifica se o nome, a versão, a cultura e a chave pública correspondem à referência do assembly chamador.
Nota
Os assemblies referenciados fora do diretório raiz do aplicativo devem ter nomes fortes e devem ser instalados no cache de assembly global ou especificados usando o <elemento codeBase> .
Localizando a montagem através de sondagem
Se não houver nenhum <elemento codeBase> no arquivo de configuração do aplicativo, o tempo de execução investigará o assembly usando quatro critérios:
Base do aplicativo, que é o local raiz onde o aplicativo está sendo executado.
Cultura, que é o atributo cultural da montagem que está sendo referenciada.
Name, que é o nome do assembly referenciado.
O
privatePath
atributo do elemento probing>< , que é a lista de subdiretórios definida pelo usuário no local raiz. Esse local pode ser especificado no arquivo de configuração do aplicativo e no código gerenciado usando a propriedade de um domínio do AppDomainSetup.PrivateBinPath aplicativo. Quando especificado no código gerenciado, o códigoprivatePath
gerenciado é investigado primeiro, seguido pelo caminho especificado no arquivo de configuração do aplicativo.
Examinando a base de aplicativos e os diretórios de cultura
O tempo de execução sempre começa a sondar na base do aplicativo, que pode ser uma URL ou o diretório raiz do aplicativo em um computador. Se o assembly referenciado não for encontrado na base do aplicativo e nenhuma informação de cultura for fornecida, o tempo de execução pesquisará quaisquer subdiretórios com o nome do assembly. Os diretórios investigados incluem:
[base do aplicativo] / [nome do assembly].dll
[Base do aplicativo] / [Nome do assembly] / [Nome do assembly].dll
Se as informações de cultura forem especificadas para o assembly referenciado, somente os seguintes diretórios serão investigados:
[base do aplicativo] / [cultura] / [nome do assembly].dll
[base do aplicativo] / [cultura] / [nome do assembly] / [nome do assembly].dll
Sondando com o atributo privatePath
Além dos subdiretórios de cultura e dos subdiretórios nomeados para o assembly referenciado, o tempo de execução também investiga diretórios especificados usando o privatePath
<atributo do elemento de sondagem.> Os diretórios especificados usando o privatePath
atributo devem ser subdiretórios do diretório raiz do aplicativo. Os diretórios investigados variam dependendo se as informações de cultura são incluídas na solicitação de assembly referenciada.
O tempo de execução para de sondar a primeira vez que encontra um assembly que corresponde ao nome de assembly simples referenciado, se é uma correspondência correta ou não. Se for uma correspondência correta, esse assembly é usado. Se não for uma correspondência correta, a sondagem para e a ligação falha.
Se a cultura estiver incluída, os seguintes diretórios serão investigados:
[Base do aplicativo] / [BinPath] / [Cultura] / [Nome do assembly].dll
[base do aplicativo] / [binpath] / [cultura] / [nome do assembly] / [nome do assembly].dll
Se as informações de cultura não forem incluídas, os seguintes diretórios serão investigados:
[Base do aplicativo] / [BinPath] / [Nome do assembly].dll
[base do aplicativo] / [binpath] / [nome do assembly] / [nome do assembly].dll
Exemplos de sondagem
Dada a seguinte informação:
Nome do assembly referenciado: myAssembly
Diretório raiz do aplicativo:
http://www.code.microsoft.com
<elemento de sondagem> no arquivo de configuração especifica: bin
Cultura: de
O tempo de execução investiga as seguintes URLs:
http://www.code.microsoft.com/de/myAssembly.dll
http://www.code.microsoft.com/de/myAssembly/myAssembly.dll
http://www.code.microsoft.com/bin/de/myAssembly.dll
http://www.code.microsoft.com/bin/de/myAssembly/myAssembly.dll
Vários assemblies com o mesmo nome
O exemplo a seguir mostra como configurar vários assemblies com o mesmo nome.
<dependentAssembly>
<assemblyIdentity name="Server" publicKeyToken="c0305c36380ba429" />
<codeBase version="1.0.0.0" href="v1/Server.dll" />
<codeBase version="2.0.0.0" href="v2/Server.dll" />
</dependentAssembly>
Outros locais sondados
O local da montagem também pode ser determinado usando o contexto de vinculação atual. Isso ocorre com mais frequência quando o Assembly.LoadFrom método é usado e em cenários de interoperabilidade COM. Se um assembly usa o LoadFrom método para fazer referência a outro assembly, o local do assembly de chamada é considerado uma dica sobre onde encontrar o assembly referenciado. Se uma correspondência for encontrada, esse assembly será carregado. Se nenhuma correspondência for encontrada, o tempo de execução continuará com sua semântica de pesquisa e, em seguida, consultará o Windows Installer para fornecer o assembly. Se nenhum assembly for fornecido que corresponda à solicitação de vinculação, uma exceção será lançada. Essa exceção é um TypeLoadException código gerenciado se um tipo foi referenciado ou um FileNotFoundException se um assembly que está sendo carregado não foi encontrado.
Por exemplo, se Assembly1 fizer referência a Assembly2 e Assembly1 foi baixado do http://www.code.microsoft.com/utils
, esse local será considerado uma dica sobre onde encontrar Assembly2.dll. Em seguida, o tempo de execução investiga o assembly em http://www.code.microsoft.com/utils/Assembly2.dll
e http://www.code.microsoft.com/utils/Assembly2/Assembly2.dll
. Se Assembly2 não for encontrado em nenhum desses locais, o tempo de execução consultará o Windows Installer.