37 votes

Comment charger un assemblage .NET pour des opérations de réflexion et le décharger ensuite ?

Je suis en train d'écrire un outil pour rapporter des informations sur les applications .NET déployées dans les environnements et les régions des systèmes de mon client.

Je voudrais lire les valeurs des attributs d'assemblage dans ces assemblages.

Cela peut être réalisé en utilisant Assembly.ReflectionOnlyLoad Cependant, même cette approche permet de maintenir l'assemblage chargé. Le problème ici est que je ne peux pas charger deux assemblages qui ont le même nom à partir de chemins différents, donc naturellement je ne peux pas comparer la même application déployée dans différents systèmes.

Pour l'instant, je suppose que la solution consistera à utiliser des dispositifs temporaires AppDomain s.

Quelqu'un peut-il expliquer en détail comment charger un assemblage dans un autre assemblage ? AppDomain de lire les attributs et de décharger l'interface de l'utilisateur. AppDomain ?

Cela doit fonctionner pour les assemblages sur le système de fichiers ainsi que ceux aux adresses URL.

48voto

Tamas Czinege Points 49277

De la Documentation MSDN de System.Reflection.Assembly.ReflectionOnlyLoad (String) :

Le contexte de réflexion seulement n'est pas différent des autres contextes. Les assemblages qui sont chargés dans le contexte ne peuvent être déchargés qu'en en déchargeant le domaine d'application.

Je crains donc que la seule façon de décharger un assemblage soit de décharger le domaine d'application. Pour créer un nouvel AppDomain et y charger des assemblages :

public void TempLoadAssembly()
{
    AppDomain tempDomain = AppDomain.CreateDomain("TemporaryAppDomain");
    tempDomain.DoCallBack(LoaderCallback);
    AppDomain.Unload(tempDomain);
}

private void LoaderCallback()
{
    Assembly.ReflectionOnlyLoad("YourAssembly");
    // Do your stuff here
}

9voto

Drew Noakes Points 69288

Bien qu'il ne s'agisse pas vraiment de décharger des assemblages, si vous essayez simplement d'obtenir le numéro de version d'un fichier, vous pouvez utiliser la méthode suivante System.Diagnostics.FileVersionInfo .

var info = FileVersionInfo.GetVersionInfo(path);

FileVersionInfo a les propriétés suivantes :

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; }

9voto

Artiom Points 1228

Vous pouvez créer une instance dans le nouveau AppDomain et exécuter votre code dans cette instance.

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);

Voici le 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;
    }
}

4voto

Ilya Ryzhenkov Points 5731

Vous pouvez essayer d'utiliser API de métadonnées non gérées qui est COM et peut facilement être utilisé à partir d'une application .NET avec une sorte de wrapper.

3voto

Albert Points 888

Vous devez utiliser les domaines d'application, il n'y a pas d'autre moyen de décharger un assemblage. En gros, vous devez utiliser un code comme celui-ci :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X