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

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?

This question is related to c# asp.net-core

The answer is


Try looking here: 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).


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!


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);

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;
}

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

I solved the problem with this code:

using System.IO;

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

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


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