¿Cómo cargar un ensamblado.NET para operaciones de reflexión y luego descargarlo?
assemblies appdomain (5)
Estoy escribiendo una herramienta para informar sobre las aplicaciones .NET implementadas en entornos y regiones dentro de los sistemas de mi cliente.
Me gustaría leer los valores de los atributos de ensamblaje en estos ensamblajes.
Esto se puede lograr usando Assembly.ReflectionOnlyLoad
, sin embargo, incluso este enfoque mantiene el ensamblaje cargado. El problema aquí es que no puedo cargar dos ensamblajes que tienen el mismo nombre desde diferentes rutas, así que, naturalmente, no puedo comparar la misma aplicación implementada en diferentes sistemas.
En este punto, asumo que la solución implicará el uso de AppDomain
s temporales.
¿Puede alguien detallar cómo cargar un ensamblado en otro AppDomain
, leer los atributos del mismo y luego descargar el AppDomain
?
Esto debe funcionar para ensamblados en el sistema de archivos y en direcciones URL.
De la documentación de MSDN de System.Reflection.Assembly.ReflectionOnlyLoad (String) :
El contexto de solo reflexión no es diferente de otros contextos. Los ensamblajes que se cargan en el contexto se pueden descargar solo descargando el dominio de la aplicación.
Por lo tanto, me temo que la única forma de descargar un ensamblaje es descargar el dominio de la aplicación. Para crear un nuevo AppDomain y cargar ensambles en él:
public void TempLoadAssembly()
{
AppDomain tempDomain = AppDomain.CreateDomain("TemporaryAppDomain");
tempDomain.DoCallBack(LoaderCallback);
AppDomain.Unload(tempDomain);
}
private void LoaderCallback()
{
Assembly.ReflectionOnlyLoad("YourAssembly");
// Do your stuff here
}
Debe usar dominios de aplicación, no hay otra forma de descargar un ensamblaje. Básicamente tienes que usar un código como este:
AppDomain tempDomain = AppDomain.CreateDomain("Temp Domain"); tempDomain.Load(assembly); AppDomain.Unload(tempDomain);
Puede crear una instancia en el nuevo AppDomain y ejecutar su código en esa instancia.
var settings = new AppDomainSetup
{
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
};
var childDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString(), null, settings);
var handle = Activator.CreateInstance(childDomain,
typeof(ReferenceLoader).Assembly.FullName,
typeof(ReferenceLoader).FullName,
false, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, null, CultureInfo.CurrentCulture, new object[0]);
var loader = (ReferenceLoader)handle.Unwrap();
//This operation is executed in the new AppDomain
var paths = loader.LoadReferences(assemblyPath);
AppDomain.Unload(childDomain);
Aquí está el ReferenceLoader
public class ReferenceLoader : MarshalByRefObject
{
public string[] LoadReferences(string assemblyPath)
{
var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
var paths = assembly.GetReferencedAssemblies().Select(x => x.FullName).ToArray();
return paths;
}
}
Puede intentar utilizar la API de metadatos no administrados , que es COM y se puede usar fácilmente desde la aplicación .NET con algún tipo de envoltorio.
Si bien no se trata realmente de descargar ensamblajes, si solo intenta obtener el número de versión de un archivo, puede usar System.Diagnostics.FileVersionInfo
.
var info = FileVersionInfo.GetVersionInfo(path);
FileVersionInfo
tiene las siguientes propiedades:
public string Comments { get; }
public string CompanyName { get; }
public int FileBuildPart { get; }
public string FileDescription { get; }
public int FileMajorPart { get; }
public int FileMinorPart { get; }
public string FileName { get; }
public int FilePrivatePart { get; }
public string FileVersion { get; }
public string InternalName { get; }
public bool IsDebug { get; }
public bool IsPatched { get; }
public bool IsPreRelease { get; }
public bool IsPrivateBuild { get; }
public bool IsSpecialBuild { get; }
public string Language { get; }
public string LegalCopyright { get; }
public string LegalTrademarks { get; }
public string OriginalFilename { get; }
public string PrivateBuild { get; }
public int ProductBuildPart { get; }
public int ProductMajorPart { get; }
public int ProductMinorPart { get; }
public string ProductName { get; }
public int ProductPrivatePart { get; }
public string ProductVersion { get; }
public string SpecialBuild { get; }