Quick one. Given any .Net app I want to know the root path of the application i.e. the top level directory. I was doing this with .Net Core but it puts in extra directories by default in the exe path i.e.
bin\Debug\netcoreapp2.0\my.dll
so my normal kuldgy methods weren’t working. This all works for any .Net app not just Core in fairness – it’s just that the extra stuffed in by .Net Core threw me a little. There are all kinds of ways to find this for particular applications web, windows etc.. but this should work generally. Well it worked with my little console app anyway.
The Code
Use reflection to targeting the executable and get the path
var rootDir = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
this will get you
file:///c:/development/MyApp/bin/Debug/netcoreapp2.0/myApp.dll
which is the UNC path. Combine with Path.GetDirectoryName i.e.
var rootDir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly. GetExecutingAssembly().CodeBase);
this gets
file:\c:\development\MyApp\bin\Debug\netcoreapp2.0
which is a file path now and it has got us the directory of the executable. It’s still not where we want to be so use some regex
(?<!fil)[A-Za-z]:\\+[\S\s]*?(?=\\+bin)
This will chop up the path and gives you
c:\development\MyApp
which is correct.
The Function
So overall a useful function for this could be
public string GetApplicationRoot() { var exePath = Path.GetDirectoryName(System.Reflection .Assembly.GetExecutingAssembly().CodeBase); Regex appPathMatcher=new Regex(@"(?<!fil)[A-Za-z]:\\+[\S\s]*?(?=\\+bin)"); var appRoot = appPathMatcher.Match(exePath).Value; return appRoot; }
Which does what we need or I quite like it as a (much abused) extension method
public static string ToApplicationPath(this string fileName) { var exePath = Path.GetDirectoryName(System.Reflection .Assembly.GetExecutingAssembly().CodeBase); Regex appPathMatcher=new Regex(@"(?<!fil)[A-Za-z]:\\+[\S\s]*?(?=\\+bin)"); var appRoot = appPathMatcher.Match(exePath).Value; return Path.Combine(appRoot, fileName); }
Which can be called like
“TargetFile.cs”.ToApplicationPath()
Which gives
c:\development\MyApp\TargetFile.cs
Job done.
The Regex
Not everyone likes Regex*. But for the aficionados here is what it is doing
(?<!fil)[A-Za-z]:\\+[\S\s]*?(?=\\+bin)
For example matching this
file:\c:\development\MyApp\bin\Debug\netcoreapp2.0
[A-Za-z]:\\+[\S\s]*?
Is my match – this will match a drive and a path up to
(?=\\+bin)
It’s a lookahead (zero length assertion). It will check for “bin” but not include it in the match
(?<!fil)
It’s a negative lookbehind (zero length assertion again). It will make sure that the letters fil don’t immediately proceed the match. This is to stop e:// being the match i.e. the e from file.
Clearly this assumes that the bin folder is directly under the root path as it normal is. If it isn’t in your app then break out your favourite Regex editor and write your own. It will make a man/woman/scared child of you.
(* Hardly anyone likes it – well I haven’t met many)
Useful Links
https://stackoverflow.com/questions/837488/how-can-i-get-the-applications-path-in-a-net-console-application
Full disclosure – the first bit of this is from this SO question. The extension I did with my very own coding fingers
http://regexstorm.net/tester
Regex storm – C# regex tester. Very good. JavaScript based testers don’t work with this as they can’t do negative lookbehinds.
https://www.regular-expressions.info/lookaround.html
Look ahead, behind and all around with zero length assertions
This isn’t specific to .netcore and fortunately you can use existing functions to retrieve the path without resorting to Regex. Give this a try: Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().Location).LocalPath); // should be platform independent as well.
wow! this is terrible! Just do this:
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)
@Graeme that doesn’t work if your debugging vs running – you get a different result. Tim’s example is the only way to to get the bin folder in all circumstances.
Here are the related github bugs:
https://github.com/dotnet/project-system/issues/589
https://github.com/dotnet/project-system/issues/2239
https://github.com/dotnet/project-system/pull/3073
But a using .Codebase with your example is the best looking and works cross platform:
Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath)
While some of the comments above may work better in the code itself, this function actually does it’s job, and survives unit testing, which the code:
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)
does not.
When compiled to an exe and run (outside of Visual Studio), both methods give me a crazy path to some ridiculous temp directory buried deep under AppData\Local. 😑
thanks, helped alot!
In Net Core 2.2 Directory.GetCurrentDirectory() return app base path.
Not cross platform. On OSX, if you double click the app, this returns the user’s home directory.
This doesn’t work for .NET STANDARD 1.4
I have a multi-target library project (net461, netstandard1.4) and already the first LOC in your example doesn’t work. ‘GetExecutingAssembly’ does not exist.
I’m trying to find a solution that works for both build targets.
Very helpful regex , saved my time .