Cómo cargar a.NET montaje para las operaciones de reflexión y posteriormente descargarlo?


Estoy escribiendo una herramienta para reportar información sobre aplicaciones.NET implementadas en entornos y regiones dentro de los sistemas de mi cliente.

Me gustaría leer los valores de los atributos de ensamblado en estos ensamblados.

Esto se puede lograr usando Assembly.ReflectionOnlyLoad, sin embargo incluso este enfoque mantiene el ensamblado cargado. El problema aquí es que no puedo cargar dos ensamblados que tengan el mismo nombre desde rutas diferentes, por lo que, naturalmente, no puedo comparar la misma aplicación implementada en diferentes sistema.

En este punto estoy asumiendo que la solución implicará el uso temporal AppDomain s.

¿Puede alguien detallar cómo cargar un ensamblado en otro AppDomain, leer los atributos de él y luego descargar el AppDomain?

Esto necesita funcionar para ensamblados en el sistema de archivos, así como para aquellos en direcciones URL.

Author: Tshepang, 2008-10-22

5 answers

De la documentación MSDN del Sistema.Reflexión.Asamblea.ReflectionOnlyLoad (Cadena) :

El contexto de solo reflexión es no diferente de otros contextos. Ensamblajes que se cargan en el el contexto solo se puede descargar mediante descarga del dominio de aplicación.

Por lo tanto, me temo que la única manera de descargar un ensamblado es descargar el dominio de la aplicación. Para crear un nuevo AppDomain y cargar ensamblados 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
}
 48
Author: Tamas Czinege,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-22 11:38:32

Aunque realmente no se trata de descargar ensamblajes, si solo está tratando de 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; }
 9
Author: Drew Noakes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-09 09:19:00

Puede intentar usar API de metadatos no administrada, que es COM y se puede usar fácilmente desde la aplicación.NET con algún tipo de envoltura.

 4
Author: Ilya Ryzhenkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-22 11:33:20

Tiene que usar dominios de aplicación, no hay otra manera de descargar un ensamblado. Básicamente tienes que usar código como este:


AppDomain tempDomain = AppDomain.CreateDomain("Temp Domain");
tempDomain.Load(assembly);
AppDomain.Unload(tempDomain);

 3
Author: Albert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-22 11:36:24

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;
    }
}
 2
Author: Artiom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-22 13:48:15