[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


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

I solved the problem with this code:

using System.IO;

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

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!


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


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

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

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

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