How to get root directory of project in asp.net core. Directory.GetCurrentDirectory() doesn't seem to work correctly on a mac

C#asp.net Core

C# Problem Overview


My project has a folder structure to the tune of:

  • Project,
  • Project/data
  • Project/Engine
  • Project/Server
  • project/front-end

In the server (running in the Project/Server folder) I refer to the folder like this:

var rootFolder = Directory.GetCurrentDirectory();
rootFolder = rootFolder.Substring(0,
            rootFolder.IndexOf(@"\Project\", StringComparison.Ordinal) + @"\Project\".Length);
PathToData = Path.GetFullPath(Path.Combine(rootFolder, "Data"));

var Parser = Parser();
var d = new FileStream(Path.Combine(PathToData, $"{dataFileName}.txt"), FileMode.Open);
var fs = new StreamReader(d, Encoding.UTF8);
      

On my windows machine this code works fine since Directory.GetCurrentDirectory() reffered to the current folder, and doing

rootFolder.Substring(0, rootFolder.IndexOf(@"\Project\", StringComparison.Ordinal) + @"\Project\".Length); 

gets me the root folder of the project (not the bin or debug folders). But when I ran it on a mac it got "Directory.GetCurrentDirectory()" sent me to /usr//[something else]. It didn't refer to the folder where my project lies.

What is the correct way to find relative paths in my project? Where should I store the data folder in a way that it is easily accessible to all the sub projects in the solution - specifically to the kestrel server project? I prefer to not have to store it in the wwwroot folder because the data folder is maintained by a different member in the team, and I just want to access the latest version. What are my options?

C# Solutions


Solution 1 - C#

Depending on where you are in the kestrel pipeline - if you have access to IConfiguration (Startup.cs constructor) or IWebHostEnvironment (formerly IHostingEnvironment) you can either inject the IWebHostEnvironment into your constructor or just request the key from the configuration.

Inject IWebHostEnvironment in Startup.cs Constructor

public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
     var contentRoot = env.ContentRootPath;
}
Using IConfiguration in Startup.cs Constructor

public Startup(IConfiguration configuration)
{
     var contentRoot = configuration.GetValue<string>(WebHostDefaults.ContentRootKey);
}

Solution 2 - C#

Working on .Net Core 2.2 and 3.0 as of now.

To get the projects root directory within a Controller:

  • Create a property for the hosting environment

     private readonly IHostingEnvironment _hostingEnvironment;
    
  • Add Microsoft.AspNetCore.Hosting to your controller

     using Microsoft.AspNetCore.Hosting;
    
  • Register the service in the constructor

     public HomeController(IHostingEnvironment hostingEnvironment) {
         _hostingEnvironment = hostingEnvironment;
     }
    
  • Now, to get the projects root path

     string projectRootPath = _hostingEnvironment.ContentRootPath;
    

To get the "wwwroot" path, use

_hostingEnvironment.WebRootPath

Solution 3 - C#

In some cases _hostingEnvironment.ContentRootPath and System.IO.Directory.GetCurrentDirectory() targets to source directory. Here is bug about it.

The solution proposed there helped me

Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);

Solution 4 - C#

As previously answered (and retracted). To get the base directory, as in the location of the running assembly, don't use Directory.GetCurrentDirectory(), rather get it from IHostingEnvironment.ContentRootPath.

private IHostingEnvironment _hostingEnvironment;
    private string projectRootFolder;
    public Program(IHostingEnvironment env)
    {
        _hostingEnvironment = env;
        projectRootFolder = env.ContentRootPath.Substring(0,
            env.ContentRootPath.LastIndexOf(@"\ProjectRoot\", StringComparison.Ordinal) + @"\ProjectRoot\".Length);
    }

However I made an additional error: I had set the ContentRoot Directory to Directory.GetCurrentDirectory() at startup undermining the default value which I had so desired! Here I commented out the offending line:

 public static void Main(string[] args)
    {
        var host = new WebHostBuilder().UseKestrel()
           // .UseContentRoot(Directory.GetCurrentDirectory()) //<== The mistake
            .UseIISIntegration()
            .UseStartup<Program>()
            .Build();
        host.Run();
    }

Now it runs correctly - I can now navigate to sub folders of my projects root with:

var pathToData = Path.GetFullPath(Path.Combine(projectRootFolder, "data"));

I realised my mistake by reading BaseDirectory vs. Current Directory and @CodeNotFound founds answer (which was retracted because it didn't work because of the above mistake) which basically can be found here: Getting WebRoot Path and Content Root Path in Asp.net Core

Solution 5 - C#

Try looking here: https://stackoverflow.com/questions/6041332/best-way-to-get-application-folder-path

To quote from there:

> System.IO.Directory.GetCurrentDirectory() returns the current > directory, which may or may not be the folder where the application is > located. The same goes for Environment.CurrentDirectory. In case you > are using this in a DLL file, it will return the path of where the > process is running (this is especially true in ASP.NET).

Solution 6 - C#

If you are using ASP.NET MVC Core 3 or newer, IHostingEnvironment has been deprecated and replaced with IWebHostEnvironment

public Startup(IWebHostEnvironment webHostEnvironment)
{
    var webRootPath = webHostEnvironment.WebRootPath;
}

Solution 7 - C#

I solved the problem with this code:

using System.IO;

var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location.Substring(0, Assembly.GetEntryAssembly().Location.IndexOf("bin\\")))

Solution 8 - C#

If that can be useful to anyone, in a Razor Page cshtml.cs file, here is how to get it: add an IHostEnvironment hostEnvironment parameter to the constructor and it will be injected automatically:

public class IndexModel : PageModel
{
    private readonly ILogger<IndexModel> _logger;
    private readonly IHostEnvironment _hostEnvironment;

    public IndexModel(ILogger<IndexModel> logger, IHostEnvironment hostEnvironment)
    {
        _logger = logger;
        _hostEnvironment = hostEnvironment; // has ContentRootPath property
    }

    public void OnGet()
    {

    }
}

PS: IHostEnvironment is in Microsoft.Extensions.Hosting namespace, in Microsoft.Extensions.Hosting.Abstractions.dll ... what a mess!

Solution 9 - C#

If using the IWebHostEnvironment via DI is not an option for you, use

AppContext.BaseDirectory

Solution 10 - C#

Based on Henrique A technique and supports Unit Test contexts as well...

ReadOnlySpan<char> appPath = Assembly.GetEntryAssembly().Location.Replace("YOURTestProject", "YOUR");
var dir = Path.GetDirectoryName(appPath.Slice(0, appPath.IndexOf("bin\\")));
string path = Path.Combine(dir.ToString(), "Resources", "countries.dat");
if (System.IO.File.Exists(path))
{
	countries = System.IO.File.ReadAllLines(path);
}

Solution 11 - C#

> It seems IHostingEnvironment has been replaced by IHostEnvironment > (and a few others). You should be able to change the interface type in > your code and everything will work as it used to :-) > > You can find more information about the changes at this link on GitHub > https://github.com/aspnet/AspNetCore/issues/7749 > > EDIT There is also an additional interface IWebHostEnvironment that > can be used in ASP.NET Core applications. This is available in the > Microsoft.AspNetCore.Hosting namespace.

Ref: https://stackoverflow.com/a/55602187/932448

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionakrainesView Question on Stackoverflow
Solution 1 - C#SliverNinja - MSFTView Answer on Stackoverflow
Solution 2 - C#StefanJMView Answer on Stackoverflow
Solution 3 - C#alehaView Answer on Stackoverflow
Solution 4 - C#akrainesView Answer on Stackoverflow
Solution 5 - C#shlgugView Answer on Stackoverflow
Solution 6 - C#DavidGView Answer on Stackoverflow
Solution 7 - C#Henrique AView Answer on Stackoverflow
Solution 8 - C#Simon MourierView Answer on Stackoverflow
Solution 9 - C#Alex from JitbitView Answer on Stackoverflow
Solution 10 - C#Jeremy ThompsonView Answer on Stackoverflow
Solution 11 - C#Ali JamalView Answer on Stackoverflow