Code Buckets

Buckets of code

.Net

Getting the Root Directory Path for .Net Core Applications

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

10 COMMENTS

  1. 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.

  2. 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. 😑

  3. 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.

LEAVE A RESPONSE

Your email address will not be published. Required fields are marked *