151 votes

Comment ajouter un dossier au chemin de recherche d'un assemblage lors de l'exécution en .NET?

Ma Dll sont chargées par l'application d'un tiers, on ne peut pas personnaliser. Mon assemblées doivent être situés dans leur propre dossier. Je ne peux pas les mettre dans le GAC (mon application doit être déployée à l'aide de la commande XCOPY). Lorsque la racine DLL essaie de charger des ressources ou de type DLL à partir d'un autre (dans le même dossier), le chargement échoue (fichier introuvable). Est-il possible d'ajouter le dossier où mon Dll sont situés à l'assemblée chemin de recherche par programme (à partir de la racine de la DLL)? Je ne suis pas autorisé à modifier les fichiers de configuration de l'application.

181voto

Mattias S Points 2674

On dirait que vous pouvez utiliser l'événement AppDomain.AssemblyResolve et charger manuellement les dépendances à partir de votre répertoire DLL.

Editer (à partir du commentaire):

 AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(LoadFromSameFolder);

static Assembly LoadFromSameFolder(object sender, ResolveEventArgs args)
{
    string folderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    string assemblyPath = Path.Combine(folderPath, new AssemblyName(args.Name).Name + ".dll");
    if (File.Exists(assemblyPath) == false) return null;
    Assembly assembly = Assembly.LoadFrom(assemblyPath);
    return assembly;
}
 

62voto

Mark Seemann Points 102767

Vous pouvez ajouter un chemin de vérification au fichier .config de votre application, mais cela ne fonctionnera que si le chemin de vérification est contenu dans le répertoire de base de votre application.

12voto

bubi Points 29

Mise à jour de Framework 4

Depuis Framework 4 soulever le AssemblyResolve cas également pour les ressources effectivement ce gestionnaire fonctionne mieux. Il est basé sur le concept que les localisations sont, en application des sous-répertoires (un pour la localisation avec le nom de la culture, c'est à dire C:\MyApp\it pour l'italien) À l'intérieur il y a des ressources de fichier. Le gestionnaire fonctionne également si la localisation est pays-région, c'est à dire-il ou pt-BR. Dans ce cas, le gestionnaire d' "peut être appelé plusieurs fois: une fois pour chaque culture dans le repli de la chaîne" [à partir de MSDN]. Cela signifie que si nous retourner la valeur null pour les "il-elle" fichier de ressources le cadre déclenche l'événement en demandant "il".

Événement crochet

        AppDomain currentDomain = AppDomain.CurrentDomain;
        currentDomain.AssemblyResolve += new ResolveEventHandler(currentDomain_AssemblyResolve);

Gestionnaire d'événements

    Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        //This handler is called only when the common language runtime tries to bind to the assembly and fails.

        Assembly executingAssembly = Assembly.GetExecutingAssembly();

        string applicationDirectory = Path.GetDirectoryName(executingAssembly.Location);

        string[] fields = args.Name.Split(',');
        string assemblyName = fields[0];
        string assemblyCulture = fields[2].Substring(fields[2].IndexOf('=') + 1);


        string assemblyFileName = assemblyName + ".dll";
        string assemblyPath;

        if (assemblyName.EndsWith(".resources"))
        {
            // Specific resources are located in app subdirectories
            string resourceDirectory = Path.Combine(applicationDirectory, assemblyCulture);

            assemblyPath = Path.Combine(resourceDirectory, assemblyFileName);
        }
        else
        {
            assemblyPath = Path.Combine(applicationDirectory, assemblyFileName);
        }



        if (File.Exists(assemblyPath))
        {
            //Load the assembly from the specified path.                    
            Assembly loadingAssembly = Assembly.LoadFrom(assemblyPath);

            //Return the loaded assembly.
            return loadingAssembly;
        }
        else
        {
            return null;
        }

    }

11voto

nawfal Points 13500

La meilleure explication de MS elle - même :

 AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);

private Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
    //This handler is called only when the common language runtime tries to bind to the assembly and fails.

    //Retrieve the list of referenced assemblies in an array of AssemblyName.
    Assembly MyAssembly, objExecutingAssembly;
    string strTempAssmbPath = "";

    objExecutingAssembly = Assembly.GetExecutingAssembly();
    AssemblyName[] arrReferencedAssmbNames = objExecutingAssembly.GetReferencedAssemblies();

    //Loop through the array of referenced assembly names.
    foreach(AssemblyName strAssmbName in arrReferencedAssmbNames)
    {
        //Check for the assembly names that have raised the "AssemblyResolve" event.
        if(strAssmbName.FullName.Substring(0, strAssmbName.FullName.IndexOf(",")) == args.Name.Substring(0, args.Name.IndexOf(",")))
        {
            //Build the path of the assembly from where it has to be loaded.                
            strTempAssmbPath = "C:\\Myassemblies\\" + args.Name.Substring(0,args.Name.IndexOf(","))+".dll";
            break;
        }

    }

    //Load the assembly from the specified path.                    
    MyAssembly = Assembly.LoadFrom(strTempAssmbPath);                   

    //Return the loaded assembly.
    return MyAssembly;          
}
 

7voto

Vincent Lidou Points 231

Rechercher dans AppDomain.AppendPrivatePath (obsolète) ou AppDomainSetup.PrivateBinPath

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