Clase System.Runtime.Loader.AssemblyLoadContext
En este artículo se proporcionan comentarios adicionales a la documentación de referencia de esta API.
AssemblyLoadContext representa un contexto de carga. Conceptualmente, un contexto de carga crea un ámbito para cargar, resolver y descargar potencialmente un conjunto de ensamblados.
AssemblyLoadContext Existe principalmente para proporcionar aislamiento de carga de ensamblados. Permite cargar varias versiones del mismo ensamblado dentro de un único proceso. Reemplaza los mecanismos de aislamiento proporcionados por varias AppDomain instancias de .NET Framework.
Nota:
- AssemblyLoadContext no proporciona ninguna característica de seguridad. Todo el código tiene permisos completos del proceso.
- Solo en .NET Core 2.0 - 2.2, AssemblyLoadContext es una clase abstracta. Para crear una clase concreta en estas versiones, implemente el AssemblyLoadContext.Load(AssemblyName) método .
Uso en tiempo de ejecución
El tiempo de ejecución implementa dos contextos de carga de ensamblados:
- AssemblyLoadContext.Default representa el contexto predeterminado del entorno de ejecución, que se usa para el ensamblado principal de la aplicación y sus dependencias estáticas.
- El Assembly.LoadFile(String) método aísla los ensamblados que carga mediante la creación de instancias del método más básico AssemblyLoadContext. Tiene un esquema de aislamiento simplista que carga cada ensamblado en su propio AssemblyLoadContext sin resolución de dependencias.
Uso de la aplicación
Una aplicación puede crear su propia AssemblyLoadContext para crear una solución personalizada para escenarios avanzados. La personalización se centra en definir mecanismos de resolución de dependencias.
AssemblyLoadContext proporciona dos puntos de extensión para implementar la resolución de ensamblados administrados:
- El AssemblyLoadContext.Load(AssemblyName) método proporciona la primera oportunidad de AssemblyLoadContext resolver, cargar y devolver el ensamblado. Si el AssemblyLoadContext.Load(AssemblyName) método devuelve
null
, el cargador intenta cargar el ensamblado en .AssemblyLoadContext.Default - Si el no AssemblyLoadContext.Default puede resolver el ensamblado, el original AssemblyLoadContext obtiene una segunda oportunidad para resolver el ensamblado. El tiempo de ejecución genera el Resolving evento .
Además, el AssemblyLoadContext.LoadUnmanagedDll(String) método virtual permite personalizar la resolución de ensamblado no administrada predeterminada. La implementación predeterminada devuelve null
, lo que hace que la búsqueda en tiempo de ejecución use su directiva de búsqueda predeterminada. La directiva de búsqueda predeterminada es suficiente para la mayoría de los escenarios.
Desafíos técnicos
No es posible cargar varias versiones del entorno de ejecución en un único proceso.
Precaución
La carga de varias copias o versiones diferentes de ensamblados de marco puede provocar un comportamiento inesperado y difícil de diagnosticar.
Sugerencia
Use límites de proceso con comunicación remota o entre procesos para resolver este problema de aislamiento.
El tiempo de carga del ensamblado puede dificultar las pruebas y la depuración. Normalmente, los ensamblados se cargan sin que se resuelvan inmediatamente sus dependencias. Las dependencias se cargan según sean necesarias:
- Cuando el código se bifurca en un ensamblado dependiente.
- Cuando el código carga recursos.
- Cuando el código carga explícitamente ensamblados.
La implementación de AssemblyLoadContext.Load(AssemblyName) puede agregar nuevas dependencias que pueden necesitar estar aisladas para permitir que existan versiones diferentes. La implementación más natural colocaría estas dependencias en el contexto predeterminado. El diseño cuidadoso puede aislar las nuevas dependencias.
El mismo ensamblado se carga varias veces en contextos diferentes.
- Esto puede provocar mensajes de error confusos, por ejemplo, "No se puede convertir el objeto de tipo "Sample.Plugin" al tipo "Sample.Plugin".
- La serialización entre límites de aislamiento no es trivial. Una solución típica consiste en usar una interfaz definida en un ensamblado que solo se carga en el contexto de carga predeterminado.