Comment obtenir le chemin de l'assembly dans lequel se trouve le code?


782

Existe-t-il un moyen d'obtenir le chemin de l'assembly dans lequel réside le code actuel? Je ne veux pas le chemin de l'assembly appelant, juste celui contenant le code.

Fondamentalement, mon test unitaire doit lire certains fichiers de test XML qui se trouvent par rapport à la DLL. Je veux que le chemin soit toujours résolu correctement, que la DLL de test soit exécutée à partir de TestDriven.NET, de l'interface graphique MbUnit ou d'autre chose.

Edit : Les gens semblent mal comprendre ce que je demande.

Ma bibliothèque de tests est située à Say

C: \ projects \ myapplication \ daotests \ bin \ Debug \ daotests.dll

et je voudrais obtenir ce chemin:

C: \ projects \ myapplication \ daotests \ bin \ Debug \

Jusqu'à présent, les trois suggestions me manquent lorsque je cours depuis le MbUnit Gui:

  • Environment.CurrentDirectory donne c: \ Program Files \ MbUnit

  • System.Reflection.Assembly.GetAssembly(typeof(DaoTests)).Location donne C: \ Documents and Settings \ george \ Local Settings \ Temp \ .... \ DaoTests.dll

  • System.Reflection.Assembly.GetExecutingAssembly().Location donne la même chose que la précédente.


102
Voici votre solution: var dir = AppDomain.CurrentDomain.BaseDirectory;
Jalal El-Shaer

7
Cela devrait être la solution acceptée. AppDomain.CurrentDomain.BaseDirectory est la bonne approche.
aBetterGamer


2
Je suis venu ici à la recherche d'une solution pour un paquet nuget pour lire un fichier JSON à partir de son répertoire pacakge. Semble que lorsqu'un package nuget est exécuté, "AppDomain.CurrentDomain.BaseDirectory" pointe vers le répertoire des projets en cours d'exécution et non vers le répertoire du package nuget. Aucun de ceux-ci ne semble cibler correctement le répertoire du package nuget.
Lucas

@Lucas non, ce ne serait pas le cas, car ce n'est pas le sujet de cette question (en fait, quand elle a été posée, nuget n'existait pas) - n'hésitez pas à commencer une nouvelle question et à me cingler dedans, mais je peux vous dire tout de suite que c'est impossible dans la plupart des cas. Pour la plupart des projets, le répertoire nuget est à packagescôté du fichier sln. MAIS lorsque vous compilez et distribuez des choses, il n'y a pas de fichier sln ni de répertoire de packages. Pendant la compilation, les éléments nécessaires (mais pas tout) sont copiés dans le répertoire bin. Le mieux est d'utiliser un script de post-construction pour copier le fichier que vous souhaitez.
George Mauer

Réponses:


1038

J'ai défini la propriété suivante car nous l'utilisons souvent dans les tests unitaires.

public static string AssemblyDirectory
{
    get
    {
        string codeBase = Assembly.GetExecutingAssembly().CodeBase;
        UriBuilder uri = new UriBuilder(codeBase);
        string path = Uri.UnescapeDataString(uri.Path);
        return Path.GetDirectoryName(path);
    }
}

La Assembly.Locationpropriété vous donne parfois des résultats amusants lorsque vous utilisez NUnit (où les assemblys s'exécutent à partir d'un dossier temporaire), donc je préfère utiliser CodeBasece qui vous donne le chemin au format URI, puis UriBuild.UnescapeDataStringsupprime le File://au début et le GetDirectoryNamechange au format Windows normal .


29
J'ai rencontré un problème, si le nom de votre répertoire est: c: \ My% 20Directory, alors Uri.UnescapeDataString retournera: c: \ My Directory Cela signifie que File.Exists ("c: \ My Directory \ MyFile.txt ") retournera false car le chemin correct est en fait" c: \ My% 20Directory \ MyFile.txt "Je suis tombé sur cela car nos chemins SVN ont des espaces et quand nous les vérifions, il les encode.
row1

5
Soyez prudent lorsque vous l'utilisez pour vérifier File.Exist () car cette méthode retournera false sur le chemin UNC. Utilisez plutôt la réponse de @ Keith.
AZ.

3
Je ne savais pas que l'on pouvait mettre l'électricité statique devant le public. Bon à savoir et je pense que je préfère pour la lisibilité
Valamas

5
Remarque: cela ne fonctionne pas avec les emplacements réseau (par exemple \\ REMOT_EPC \ Folder)
Muxa

5
Cela ne fonctionnera pas non plus si le répertoire contient des signes numériques «#». Les signes numériques sont autorisés dans les noms de répertoire et de fichier sous Windows.
Huemac

322

est-ce que cela aide?

//get the full location of the assembly with DaoTests in it
string fullPath = System.Reflection.Assembly.GetAssembly(typeof(DaoTests)).Location;

//get the folder that's in
string theDirectory = Path.GetDirectoryName( fullPath );

voir mon montage, ce n'est pas le cas, est-ce quelque chose d'étrange sur la façon dont MbUnit fait les choses?
George Mauer

3
Définissez les fichiers xml pour qu'ils soient du contenu, copiés avec la dll ou des ressources, lues à partir de la dll.
Keith

22
Ou tout simplementtypeof(DaoTests).Assembly
SLaks

4
@SLaks @JohnySkovdal @Keith: Hé les gars, utilisez Assembly.GetExecutingAssembly(). Il "obtient l'assembly qui contient le code en cours d'exécution" (à partir de la description de la méthode). J'utilise ceci dans mon AddIn " EntitiesToDTOs ". Voir AssemblyHelper.cs pour un exemple réel.
kzfabi

4
Nous avons eu un problème avec le message de @John Silby, car il ne semble pas que cela fonctionne pour les chemins UNC ... par exemple \\ Server \ Folder \ File.ext. Celui-ci a fait l'affaire. +1
Blueberry

312

C'est aussi simple que ça:

var dir = AppDomain.CurrentDomain.BaseDirectory;

11
Cela devrait être la solution acceptée. AppDomain.CurrentDomain.BaseDirectory est la bonne approche.
aBetterGamer

5
merci d'avoir attiré mon attention sur ce point - je ne sais pas si c'était disponible au moment où j'ai posé la question, mais c'est maintenant.
George Mauer

120
Non, c'est faux. Cela renvoie le chemin du POINT D'ENTRÉE ORIGINAL et non le code en cours d'exécution. Si vous avez chargé un assemblage manuellement à partir d'un chemin différent, ou s'il a été chargé à partir de GAC, il retournera le mauvais résultat. Cette réponse est correcte: stackoverflow.com/a/283917/243557 est plus rapide encore Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).
nathanchere

9
En fait, cela ne fonctionnera pas dans les applications Web, mais pour autant que j'ai trouvé l'augmentation suivante devrait fonctionner pour tout type d'application:AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory
Ilya Chernomordik

4
Ceci est excellent pour les tests unitaires si vous voulez simplement obtenir le chemin du bac d'origine de votre ensemble de test (par exemple, pour atteindre les fichiers de données auxiliaires dans les sous-dossiers). L'assemblage de test est le point d'entrée de votre code.
MarioDS

68

Identique à la réponse de John, mais une méthode d'extension légèrement moins détaillée.

public static string GetDirectoryPath(this Assembly assembly)
{
    string filePath = new Uri(assembly.CodeBase).LocalPath;
    return Path.GetDirectoryName(filePath);            
}

Vous pouvez maintenant:

var localDir = Assembly.GetExecutingAssembly().GetDirectoryPath();

ou si vous préférez:

var localDir = typeof(DaoTests).Assembly.GetDirectoryPath();

6
Voulez-vous dire assemblyau lieu de Assembly.GetExecutingAssembly()?
Mec Pascalou

3
Comme le fait remarquer Dude, vous avez transmis un argument et vous ne l'avez pas utilisé.
Chris Moschini

4
Cette réponse est tout simplement fausse pour la question posée. Une version modifiée de cette réponse pourrait vous donner le chemin d'un assemblage donné. Cependant, ici, nous recherchons spécifiquement l'assembly en cours d'exécution, et la transmission d'un assembly n'a donc aucun sens. Une méthode d'extension n'est pas le bon outil pour le travail.
Edward Brey

46

La seule solution qui a fonctionné pour moi lors de l'utilisation des partages CodeBase et UNC Network était:

System.IO.Path.GetDirectoryName(new System.Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath);

Il fonctionne également avec les URI normaux.


5
Ce devrait être la réponse acceptée. C'est vraiment ennuyeux que la base de code par défaut ne gère pas correctement les partages UNC.
Daniel Gilbert

Cela tombe en panne lorsque le dossier contient des espaces et Dieu sait quels autres personnages ...
MarioDS

1
Je l'utilise beaucoup et j'ai trouvé un scénario où cela échoue: si cette ligne de code elle-même fait partie d'un package NuGet qui est ensuite utilisé par une application! Nous pouvons également soutenir ce scénario en remplaçant GetExecutingAssembly()par GetCallingAssembly().
Timo

@Timo: avez-vous vérifié si ce changement a des effets secondaires? Si c'est le cas, veuillez modifier la réponse pour inclure le correctif.
Ignacio Soler Garcia

@IgnacioSolerGarcia Malheureusement, je dois signaler que cela n'a fonctionné qu'une couche en profondeur, c'est-à-dire qu'il échoue si le package NuGet a été appelé par un autre package NuGet! J'utilise maintenant ce (d'un commentaire sur cette page par Chernomordik): AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory. La première partie est destinée aux applications Web et la seconde aux autres applications.
Timo

32

Cela devrait fonctionner, sauf si l'assembly est copié en double :

string path = System.Reflection.Assembly.GetExecutingAssembly().Location

14

Et ça:

System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

11

Je soupçonne que le vrai problème ici est que votre exécuteur de test copie votre assemblage vers un emplacement différent. Il n'y a aucun moyen au moment de l'exécution de dire d'où l'assembly a été copié, mais vous pouvez probablement actionner un commutateur pour dire au testeur d'exécuter l'assembly à partir de son emplacement et de ne pas le copier dans un répertoire caché.

Un tel commutateur est susceptible d'être différent pour chaque testeur, bien sûr.

Avez-vous envisagé d'intégrer vos données XML en tant que ressources dans votre assembly de test?


+1 pour avoir signalé le problème des clichés instantanés. Cependant, il est en effet possible de déterminer l'emplacement d'origine à partir du Assembly.CodeBase.
tm1

11
AppDomain.CurrentDomain.BaseDirectory

fonctionne avec MbUnit GUI.


Cela a très bien fonctionné pour écrire un fichier relatif au répertoire racine dans une application web asp.net
Philip Pittle

J'ai trouvé que celui-ci fonctionne mieux en général. Choisissez-le si vous n'êtes pas sûr.
Erik Bergstedt

10

Je crois que cela fonctionnerait pour tout type d'application:

AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory

1
Mes expériences montrent que c'est la réponse la plus infaillible, couvrant non seulement les applications Web et console, mais aussi les appels des tests unitaires et des packages NuGet (imbriqués à n'importe quel niveau de récursivité).
Timo

8

Pour autant que je sache, la plupart des autres réponses ont quelques problèmes.

La façon correcte de le faire pour un assembly basé sur disque (par opposition à basé sur le Web), non GACed est d'utiliser la CodeBasepropriété de l'assembly en cours d'exécution .

Cela renvoie une URL ( file://). Au lieu de jouer avec la manipulation de chaînes ou UnescapeDataString, cela peut être converti avec un minimum d'agitation en tirant parti de la LocalPathpropriété de Uri.

var codeBaseUrl = Assembly.GetExecutingAssembly().CodeBase;
var filePathToCodeBase = new Uri(codeBaseUrl).LocalPath;
var directoryPath = Path.GetDirectoryName(filePathToCodeBase);

1
Ne fonctionne pas si le chemin contient #( EscapedCodeBasefonctionne, mais EscapedCodeBase ne fonctionne pas si le chemin contient par exemple %20verbatim (qui est une séquence de caractères autorisée dans un chemin Windows))
Martin Ba

Si nous voulons avoir ce code dans un package NuGet, nous pouvons corriger ce scénario en le remplaçant GetExecutingAssembly()par GetCallingAssembly().
Timo

8

Que dis-tu de ça ...

string ThisdllDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

Ensuite, piratez simplement ce dont vous n'avez pas besoin


7
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyPath = assembly.GetFiles()[0].Name;
var assemblyDir = System.IO.Path.GetDirectoryName(assemblyPath);

7

Voici un port VB.NET du code de John Sibly. Visual Basic n'est pas sensible à la casse, donc quelques-uns de ses noms de variables entraient en collision avec des noms de type.

Public Shared ReadOnly Property AssemblyDirectory() As String
    Get
        Dim codeBase As String = Assembly.GetExecutingAssembly().CodeBase
        Dim uriBuilder As New UriBuilder(codeBase)
        Dim assemblyPath As String = Uri.UnescapeDataString(uriBuilder.Path)
        Return Path.GetDirectoryName(assemblyPath)
    End Get
End Property

6

Pendant toutes ces années, personne n'a vraiment mentionné celui-ci. Une astuce que j'ai apprise du génial projet ApprovalTests . L'astuce consiste à utiliser les informations de débogage dans l'assembly pour rechercher le répertoire d'origine.

Cela ne fonctionnera pas en mode RELEASE, ni avec les optimisations activées, ni sur une machine différente de celle sur laquelle elle a été compilée.

Mais cela vous donnera des chemins relatifs à l'emplacement du fichier de code source à partir duquel vous l'appelez

public static class PathUtilities
{
    public static string GetAdjacentFile(string relativePath)
    {
        return GetDirectoryForCaller(1) + relativePath;
    }
    public static string GetDirectoryForCaller()
    {
        return GetDirectoryForCaller(1);
    }


    public static string GetDirectoryForCaller(int callerStackDepth)
    {
        var stackFrame = new StackTrace(true).GetFrame(callerStackDepth + 1);
        return GetDirectoryForStackFrame(stackFrame);
    }

    public static string GetDirectoryForStackFrame(StackFrame stackFrame)
    {
        return new FileInfo(stackFrame.GetFileName()).Directory.FullName + Path.DirectorySeparatorChar;
    }
}

5

Le répertoire courant où vous existez.

Environment.CurrentDirectory;  // This is the current directory of your application

Si vous copiez le fichier .xml avec build, vous devriez le trouver.

ou

System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(SomeObject));

// The location of the Assembly
assembly.Location;

cela sera problématique si l'assemblage a été copié en double .
dépenser le

+1520! Environment.CurrentDirectoryfonctionne si vous utilisez la réflexion dans la classe de tâches MSBuild, où l'assembly en cours d'exécution réside dans GAC et où votre code est ailleurs.
vulcan raven

4
En général, CurrentDirectory ne vous dit pas où résident vos exécutables. Ce n'est pas à ça qu'il sert. Il se trouve que c'est souvent au même endroit que les exécutables, donc beaucoup de programmeurs ne comprennent pas la différence. Ensuite, ils finissent par créer des problèmes pour certains des utilisateurs finaux qui s'attendaient à ce que l'application comprenne la bonne utilisation de CurrentDirectory.
Bent Tranberg

5

J'ai utilisé Assembly.CodeBase au lieu de Location:

Assembly a;
a = Assembly.GetAssembly(typeof(DaoTests));
string s = a.CodeBase.ToUpper(); // file:///c:/path/name.dll
Assert.AreEqual(true, s.StartsWith("FILE://"), "CodeBase is " + s);
s = s.Substring(7, s.LastIndexOf('/') - 7); // 7 = "file://"
while (s.StartsWith("/")) {
    s = s.Substring(1, s.Length - 1);
}
s = s.Replace("/", "\\");

Cela fonctionne, mais je ne suis plus sûr qu'il soit correct à 100%. La page à http://blogs.msdn.com/suzcook/archive/2003/06/26/assembly-codebase-vs-assembly-location.aspx dit:

"Le CodeBase est une URL vers l'endroit où le fichier a été trouvé, tandis que l'emplacement est le chemin où il a été réellement chargé. Par exemple, si l'assembly a été téléchargé à partir d'Internet, son CodeBase peut commencer par" http: // " , mais son emplacement peut commencer par "C: \". Si le fichier a été copié en double, l'emplacement sera le chemin d'accès à la copie du fichier dans le répertoire de cliché instantané. Il est également bon de savoir que le CodeBase n'est pas garanti à définir pour les assemblys dans le GAC. Cependant, l'emplacement sera toujours défini pour les assemblys chargés à partir du disque. "

Vous pouvez utiliser CodeBase au lieu de Location.


1
@Kiquenet: Autant de code juste pour convertir un URI en chemin. Bien sûr, cela pourrait être amélioré. Regardez la réponse de Mike Schall ou SoMoS. Vous ne devez pas essayer de convertir les URI au niveau de la chaîne, mais plutôt utiliser les objets appropriés. OK, il est également maladroit que Assembly.CodeBase renvoie une chaîne au lieu d'un objet plus approprié, comme URI ou FileInfo.
Sept

2

Vous pouvez obtenir le chemin du bac par AppDomain.CurrentDomain.RelativeSearchPath


2

Toutes les réponses proposées fonctionnent lorsque le développeur peut modifier le code pour inclure l'extrait de code requis, mais si vous souhaitez le faire sans modifier le code, vous pouvez utiliser Process Explorer.

Il répertorie toutes les DLL en cours d'exécution sur le système, vous devrez peut-être déterminer l'ID de processus de votre application en cours d'exécution, mais ce n'est généralement pas trop difficile.

J'ai écrit une description complète de la façon de procéder pour une DLL à l'intérieur de II - http://nodogmablog.bryanhogan.net/2016/09/locating-and-checking-an-executing-dll-on-a-running-web -serveur/


Notez que tout d'abord, le code de l'article est assez centré sur IIS et deuxièmement, il vous donne (je crois) toutes les DLL actuellement chargées , pas ce qui s'exécute à un moment donné.
George Mauer

L'exemple donné concerne iis, mais les mêmes étapes s'appliquent si la DLL s'exécute dans un processus en dehors d'iis. Il s'agit simplement d'identifier l'ID du processus. Je mettrai à jour l'article pour le noter. Merci pour la suggestion.
Bryan

2

dans une application de formulaire Windows, vous pouvez simplement utiliser Application.StartupPath

mais pour les DLL et les applications console, le code est beaucoup plus difficile à retenir ...

string slash = Path.DirectorySeparatorChar.ToString();
string root = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

root += slash;
string settingsIni = root + "settings.ini"


1

Vous obtiendrez un répertoire incorrect si un chemin contient le symbole «#». J'utilise donc une modification de la réponse de John Sibly qui est la combinaison UriBuilder.Path et UriBuilder.Fragment:

public static string AssemblyDirectory
{
    get
    {
        string codeBase = Assembly.GetExecutingAssembly().CodeBase;
        UriBuilder uri = new UriBuilder(codeBase);
        //modification of the John Sibly answer    
        string path = Uri.UnescapeDataString(uri.Path.Replace("/", "\\") + 
          uri.Fragment.Replace("/", "\\"));
        return Path.GetDirectoryName(path);
     }
}

0

C'est ce que j'ai trouvé. Entre les projets Web, tests unitaires (exécuteur de test de nunit et resharper) ; J'ai trouvé que cela fonctionnait pour moi.

Je cherchais code pour détecter quelle configuration la construction est, Debug/Release/CustomName. Hélas, le #if DEBUG. Donc, si quelqu'un peut améliorer cela !

N'hésitez pas à modifier et à améliorer.

Obtention du dossier d'application . Utile pour les racines web, unittests pour obtenir le dossier des fichiers de test.

public static string AppPath
{
    get
    {
        DirectoryInfo appPath = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);

        while (appPath.FullName.Contains(@"\bin\", StringComparison.CurrentCultureIgnoreCase)
                || appPath.FullName.EndsWith(@"\bin", StringComparison.CurrentCultureIgnoreCase))
        {
            appPath = appPath.Parent;
        }
        return appPath.FullName;
    }
}

Obtenir le dossier bin : utile pour exécuter des assemblys à l'aide de la réflexion. Si des fichiers y sont copiés en raison de propriétés de construction.

public static string BinPath
{
    get
    {
        string binPath = AppDomain.CurrentDomain.BaseDirectory;

        if (!binPath.Contains(@"\bin\", StringComparison.CurrentCultureIgnoreCase)
            && !binPath.EndsWith(@"\bin", StringComparison.CurrentCultureIgnoreCase))
        {
            binPath = Path.Combine(binPath, "bin");
            //-- Please improve this if there is a better way
            //-- Also note that apps like webapps do not have a debug or release folder. So we would just return bin.
#if DEBUG
            if (Directory.Exists(Path.Combine(binPath, "Debug"))) 
                        binPath = Path.Combine(binPath, "Debug");
#else
            if (Directory.Exists(Path.Combine(binPath, "Release"))) 
                        binPath = Path.Combine(binPath, "Release");
#endif
        }
            return binPath;
    }
}

0

Cela devrait fonctionner:

ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
Assembly asm = Assembly.GetCallingAssembly();
String path = Path.GetDirectoryName(new Uri(asm.EscapedCodeBase).LocalPath);

string strLog4NetConfigPath = System.IO.Path.Combine(path, "log4net.config");

J'utilise ceci pour déployer des bibliothèques de fichiers DLL avec un fichier de configuration (c'est pour utiliser log4net à partir du fichier DLL).


À quoi fileMapsert ici?
George Mauer

0

Je trouve ma solution adéquate pour la récupération de l'emplacement.

var executingAssembly = new FileInfo((Assembly.GetExecutingAssembly().Location)).Directory.FullName;

C'est déjà l'une des réponses les mieux notées et est mentionnée explicitement dans la question comme quelque chose qui ne fonctionne pas dans cette situation.
George Mauer

Les excuses doivent avoir raté ça! De toute évidence, je n'ai pas lu attentivement.
Tez Wingfield

0

J'ai eu le même comportement NUnitdans le passé. Par défaut, NUnitcopie votre assembly dans le répertoire temporaire. Vous pouvez modifier ce comportement dans les NUnitparamètres:

entrez la description de l'image ici

Peut TestDriven.NET- être que l' MbUnitinterface graphique a les mêmes paramètres.


-3

J'utilise ceci pour obtenir le chemin vers le répertoire Bin:

var i = Environment.CurrentDirectory.LastIndexOf(@"\");
var path = Environment.CurrentDirectory.Substring(0,i); 

Vous obtenez ce résultat:

"c: \ users \ ricooley \ documents \ visual studio 2010 \ Projects \ Windows_Test_Project \ Windows_Test_Project \ bin"


6
Je ne vois pas de raison d'éviter Path.getDirectoryName ici
Max Keller

@MaxKeller Si vous ne voyez pas de raisons, cela ne signifie pas que c'est juste. Cette méthode alternative de Path.GetDirectoryName est dix fois plus rapide.
Ruslan Veselov

-3

Application Web?

Server.MapPath("~/MyDir/MyFile.ext")

2
@christiandev c'est une réponse mais cela semble peut-être être une réponse à la mauvaise question. D'après la question, il est assez clair que ce n'est pas une application Web mais un assemblage exécuté avec MbUnit. Cela étant dit, la réponse n'est toujours pas vraiment correcte en raison du cliché instantané Asp.Net (bien que cela puisse éventuellement être ce que quelqu'un atterrissant sur cette question recherche).
George Mauer
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.