Compreendendo System. Runtime. Loader. AssemblyLoadContextUnderstanding System.Runtime.Loader.AssemblyLoadContext

A classe AssemblyLoadContext é exclusiva do .NET Core.The AssemblyLoadContext class is unique to .NET Core. Este artigo tenta complementar a documentação da API AssemblyLoadContext com informações conceituais.This article attempts to supplement the AssemblyLoadContext API documentation with conceptual information.

Este artigo é relevante para os desenvolvedores que implementam o carregamento dinâmico, especialmente os desenvolvedores de estrutura de carregamento dinâmico.This article is relevant to developers implementing dynamic loading, especially dynamic loading framework developers.

O que é o AssemblyLoadContext?What is the AssemblyLoadContext?

Cada aplicativo .NET Core usa implicitamente o AssemblyLoadContext.Every .NET Core application implicitly uses the AssemblyLoadContext. É o provedor do tempo de execução para localizar e carregar dependências.It's the runtime's provider for locating and loading dependencies. Sempre que uma dependência é carregada, uma instância AssemblyLoadContext é chamada para localizá-la.Whenever a dependency is loaded, an AssemblyLoadContext instance is invoked to locate it.

  • Ele fornece um serviço de localizar, carregar e armazenar em cache assemblies gerenciados e outras dependências.It provides a service of locating, loading, and caching managed assemblies and other dependencies.

  • Para dar suporte ao carregamento e descarregamento de código dinâmico, ele cria um contexto isolado para carregar o código e suas dependências em sua própria instância AssemblyLoadContext.To support dynamic code loading and unloading, it creates an isolated context for loading code and its dependencies in their own AssemblyLoadContext instance.

Quando você precisa de várias instâncias de AssemblyLoadContext?When do you need multiple AssemblyLoadContext instances?

Uma única instância AssemblyLoadContext é limitada a carregar exatamente uma versão de um Assembly por nome de assembly simples, AssemblyName.Name.A single AssemblyLoadContext instance is limited to loading exactly one version of an Assembly per simple assembly name, AssemblyName.Name.

Essa restrição pode se tornar um problema ao carregar módulos de código dinamicamente.This restriction can become a problem when loading code modules dynamically. Cada módulo é compilado de forma independente e pode depender de versões diferentes de um Assembly.Each module is independently compiled and may depend on different versions of an Assembly. Esse problema geralmente ocorre quando diferentes módulos dependem de versões diferentes de uma biblioteca comumente usada.This problem commonly occurs when different modules depend on different versions of a commonly used library.

Para dar suporte ao carregamento dinâmico de código, a API AssemblyLoadContext fornece o carregamento de versões conflitantes de um Assembly no mesmo aplicativo.To support dynamically loading code, the AssemblyLoadContext API provides for loading conflicting versions of an Assembly in the same application. Cada instância AssemblyLoadContext fornece um mapeamento de dicionário exclusivo de cada AssemblyName.Name para uma instância Assembly específica.Each AssemblyLoadContext instance provides a unique dictionary mapping each AssemblyName.Name to a specific Assembly instance.

Ele também fornece um mecanismo conveniente para agrupar dependências relacionadas a um módulo de código para descarregamento posterior.It also provides a convenient mechanism for grouping dependencies related to a code module for later unload.

O que é especial sobre a instância AssemblyLoadContext. Default?What is special about the AssemblyLoadContext.Default instance?

A instância AssemblyLoadContext.Default é preenchida automaticamente pelo tempo de execução na inicialização.The AssemblyLoadContext.Default instance is automatically populated by the runtime at startup. Ele usa a investigação padrão para localizar e localizar todas as dependências estáticas.It uses default probing to locate and find all static dependencies.

Ele resolve os cenários de carregamento de dependência mais comuns.It solves the most common dependency loading scenarios.

Como o AssemblyLoadContext dá suporte a dependências dinâmicas?How does AssemblyLoadContext support dynamic dependencies?

AssemblyLoadContext tem vários eventos e funções virtuais que podem ser substituídos.AssemblyLoadContext has various events and virtual functions that can be overridden.

A instância AssemblyLoadContext.Default dá suporte apenas à substituição dos eventos.The AssemblyLoadContext.Default instance only supports overriding the events.

Os artigos algoritmos de carregamento de assembly gerenciado, algoritmo de carregamento de assembly satélitee algoritmo de carregamento de biblioteca não gerenciada (nativa) referem-se a todos os eventos e funções virtuais disponíveis.The articles Managed assembly loading algorithm, Satellite assembly loading algorithm, and Unmanaged (native) library loading algorithm refer to all the available events and virtual functions. Os artigos mostram cada evento e a posição relativa da função nos algoritmos de carregamento.The articles show each event and function's relative position in the loading algorithms. Este artigo não reproduz essas informações.This article doesn't reproduce that information.

Esta seção aborda os princípios gerais para os eventos e funções relevantes.This section covers the general principles for the relevant events and functions.

  • Ser repetível.Be repeatable. Uma consulta para uma dependência específica sempre deve resultar na mesma resposta.A query for a specific dependency must always result in the same response. A mesma instância de dependência carregada deve ser retornada.The same loaded dependency instance must be returned. Esse requisito é fundamental para a consistência do cache.This requirement is fundamental for cache consistency. Para assemblies gerenciados em particular, estamos criando um cache Assembly.For managed assemblies in particular, we're creating a Assembly cache. A chave de cache é um nome de assembly simples, AssemblyName.Name.The cache key is a simple assembly name, AssemblyName.Name.
  • Normalmente não geram.Typically don't throw. Espera-se que essas funções retornem null em vez de throw quando não for possível localizar a dependência solicitada.It's expected that these functions return null rather than throw when unable to find the requested dependency. A geração encerrará prematuramente a pesquisa e será propagada uma exceção para o chamador.Throwing will prematurely end the search and be propagate an exception to the caller. O lançamento deve ser restrito a erros inesperados, como um assembly corrompido ou uma condição de memória insuficiente.Throwing should be restricted to unexpected errors like a corrupted assembly or an out of memory condition.
  • Evite a recursão.Avoid recursion. Lembre-se de que essas funções e manipuladores implementam as regras de carregamento para localizar dependências.Be aware that these functions and handlers implement the loading rules for locating dependencies. Sua implementação não deve chamar APIs que disparam a recursão.Your implementation shouldn't call APIs that trigger recursion. Seu código normalmente deve chamar funções de carregamento AssemblyLoadContext que exigem um caminho específico ou um argumento de referência de memória.Your code should typically call AssemblyLoadContext load functions that require a specific path or memory reference argument.
  • Carregue no AssemblyLoadContext correto.Load into the correct AssemblyLoadContext. A escolha de onde carregar dependências é específica do aplicativo.The choice of where to load dependencies is application-specific. A escolha é implementada por esses eventos e funções.The choice is implemented by these events and functions. Quando seu código chama o AssemblyLoadContext , as funções carregadas por caminho as chamam na instância em que você deseja que o código seja carregado.When your code calls AssemblyLoadContext load-by-path functions call them on the instance where you want the code loaded. Ao retornar null e deixar o identificador de AssemblyLoadContext.Default a carga pode ser a opção mais simples.Sometime returning null and letting the AssemblyLoadContext.Default handle the load may be the simplest option.
  • Lembre-se de corridas de thread.Be aware of thread races. O carregamento pode ser disparado por vários threads.Loading can be triggered by multiple threads. O AssemblyLoadContext lida com corridas de thread por meio da adição atômica de assemblies ao seu cache.The AssemblyLoadContext handles thread races by atomically adding assemblies to its cache. A instância do perdedor da corrida é descartada.The race loser's instance is discarded. Na lógica de implementação, não adicione uma lógica extra que não manipule vários threads corretamente.In your implementation logic, don't add extra logic that doesn't handle multiple threads properly.

Como as dependências dinâmicas são isoladas?How are dynamic dependencies isolated?

Cada instância AssemblyLoadContext representa um escopo exclusivo para as definições Assembly e Type.Each AssemblyLoadContext instance represents a unique scope for Assembly instances and Type definitions.

Não há nenhum isolamento binário entre essas dependências.There's no binary isolation between these dependencies. Eles são isolados apenas por não encontrar um ao outro por nome.They're only isolated by not finding each other by name.

Em cada AssemblyLoadContext:In each AssemblyLoadContext:

Como as dependências são compartilhadas?How are dependencies shared?

As dependências podem ser facilmente compartilhadas entre instâncias AssemblyLoadContext.Dependencies can easily be shared between AssemblyLoadContext instances. O modelo geral é para um AssemblyLoadContext para carregar uma dependência.The general model is for one AssemblyLoadContext to load a dependency. O outro compartilha a dependência usando uma referência ao assembly carregado.The other shares the dependency by using a reference to the loaded assembly.

Esse compartilhamento é necessário para os assemblies de tempo de execução.This sharing is required of the runtime assemblies. Esses assemblies só podem ser carregados no AssemblyLoadContext.Default.These assemblies can only be loaded into the AssemblyLoadContext.Default. O mesmo é necessário para estruturas como ASP.NET, WPF ou WinForms.The same is required for frameworks like ASP.NET, WPF, or WinForms.

É recomendável que as dependências compartilhadas sejam carregadas em AssemblyLoadContext.Default.It's recommended that shared dependencies should be loaded into AssemblyLoadContext.Default. Esse compartilhamento é o padrão de design comum.This sharing is the common design pattern.

O compartilhamento é implementado na codificação da instância personalizada AssemblyLoadContext.Sharing is implemented in the coding of the custom AssemblyLoadContext instance. AssemblyLoadContext tem vários eventos e funções virtuais que podem ser substituídos.AssemblyLoadContext has various events and virtual functions that can be overridden. Quando qualquer uma dessas funções retorna uma referência a uma instância Assembly que foi carregada em outra instância AssemblyLoadContext, a instância Assembly é compartilhada.When any of these functions return a reference to an Assembly instance that was loaded in another AssemblyLoadContext instance, the Assembly instance is shared. O algoritmo de carga padrão é adiado para AssemblyLoadContext.Default para carregar a fim de simplificar o padrão de compartilhamento comum.The standard load algorithm defers to AssemblyLoadContext.Default for loading to simplify the common sharing pattern. Consulte algoritmo de carregamento de assembly gerenciado.See Managed assembly loading algorithm.

ComplicaçõesComplications

Problemas de conversão de tipoType conversion issues

Quando duas instâncias AssemblyLoadContext contêm definições de tipo com o mesmo name, elas não são do mesmo tipo.When two AssemblyLoadContext instances contain type definitions with the same name, they're not the same type. Eles serão do mesmo tipo se forem provenientes da mesma instância Assembly.They're the same type if and only if they come from the same Assembly instance.

Para complicar as coisas, as mensagens de exceção sobre esses tipos incompatíveis podem ser confusas.To complicate matters, exception messages about these mismatched types can be confusing. Os tipos são referenciados nas mensagens de exceção por seus nomes de tipo simples.The types are referred to in the exception messages by their simple type names. A mensagem de exceção comum, neste caso, seria a forma:The common exception message in this case would be of the form:

O objeto do tipo ' Isolatype ' não pode ser convertido para o tipo ' Isolatype '.Object of type 'IsolatedType' cannot be converted to type 'IsolatedType'.

Problemas de conversão de tipo de depuraçãoDebugging type conversion issues

Dado um par de tipos incompatíveis, é importante também saber:Given a pair of mismatched types it's important to also know:

Dado dois objetos a e b, a avaliação do seguinte no depurador será útil:Given two objects a and b, evaluating the following in the debugger will be helpful:

// In debugger look at each assembly's instance, Location, and FullName
a.GetType().Assembly
b.GetType().Assembly
// In debugger look at each AssemblyLoadContext's instance and name
System.Runtime.AssemblyLoadContext.GetLoadContext(a.GetType().Assembly)
System.Runtime.AssemblyLoadContext.GetLoadContext(b.GetType().Assembly)

Resolvendo problemas de conversão de tipoResolving type conversion issues

Há dois padrões de design para resolver esses problemas de conversão de tipo.There are two design patterns for solving these type conversion issues.

  1. Use tipos compartilhados comuns.Use common shared types. Esse tipo compartilhado pode ser um tipo de tempo de execução primitivo ou pode envolver a criação de um novo tipo compartilhado em um assembly compartilhado.This shared type can either be a primitive runtime type, or it can involve creating a new shared type in a shared assembly. Geralmente, o tipo compartilhado é uma interface definida em um assembly de aplicativo.Often the shared type is an interface defined in an application assembly. Confira também: Como as dependências são compartilhadas?.See also: How are dependencies shared?.

  2. Use técnicas de marshaling para converter de um tipo para outro.Use marshaling techniques to convert from one type to another.