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 CoreC# 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/
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.
IWebHostEnvironment
in Startup.cs
Constructor
Inject 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.