简体   繁体   English

如何在 asp.net 内核中获取项目的根目录。 Directory.GetCurrentDirectory() 在 Mac 上似乎无法正常工作

[英]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:在服务器(在 Project/Server 文件夹中运行)中,我指的是这样的文件夹:

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在我的 windows 机器上,此代码工作正常,因为Directory.GetCurrentDirectory()引用了当前文件夹,并且正在执行

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

gets me the root folder of the project (not the bin or debug folders).获取项目的根文件夹(不是 bin 或 debug 文件夹)。 But when I ran it on a mac it got " Directory.GetCurrentDirectory() " sent me to /usr//[something else].但是当我在 Mac 上运行它时,它得到了“ Directory.GetCurrentDirectory() ”将我发送到 /usr//[其他东西]。 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.我宁愿不必将其存储在 wwwroot 文件夹中,因为数据文件夹由团队中的其他成员维护,我只想访问最新版本。 What are my options?我有哪些选择?

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.根据您在 kestrel 管道中的位置 - 如果您有权访问IConfigurationStartup.cs构造函数)或IWebHostEnvironment以前称为IHostingEnvironment ),您可以将IWebHostEnvironment注入您的构造函数或仅从配置中请求密钥。

Inject IWebHostEnvironment in Startup.cs ConstructorStartup.cs构造函数中注入IWebHostEnvironment

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

Using IConfiguration in Startup.cs Constructor 在 Startup.cs 构造函数中使用 IConfiguration

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

Working on .Net Core 2.2 and 3.0 as of now.目前在 .Net Core 2.2 和 3.0 上工作。

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将 Microsoft.AspNetCore.Hosting 添加到您的控制器

    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要获取“ wwwroot ”路径,请使用

_hostingEnvironment.WebRootPath

In some cases _hostingEnvironment.ContentRootPath and System.IO.Directory.GetCurrentDirectory() targets to source directory.在某些情况下_hostingEnvironment.ContentRootPathSystem.IO.Directory.GetCurrentDirectory()目标到源目录。 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.要获取基本目录(如运行程序集的位置),请不要使用 Directory.GetCurrentDirectory(),而是从 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!但是我犯了一个额外的错误:我在启动时将 ContentRoot Directory 设置为 Directory.GetCurrentDirectory() 破坏了我想要的默认值! 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我通过阅读BaseDirectory vs. Current Directory和 @CodeNotFound founds 来意识到我的错误(由于上述错误而被撤回,因为它不起作用),基本上可以在这里找到: Getting WebRoot Path and Content Root Path in Asp.net核

Try looking here: Best way to get application folder path试试看这里: 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. System.IO.Directory.GetCurrentDirectory()返回当前目录,该目录可能是也可能不是应用程序所在的文件夹。 The same goes for Environment.CurrentDirectory. 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).如果您在 DLL 文件中使用它,它将返回进程运行的路径(这在 ASP.NET 中尤其如此)。

If you are using ASP.NET MVC Core 3 or newer, IHostingEnvironment has been deprecated and replaced with IWebHostEnvironment如果您使用的是 ASP.NET MVC Core 3 或更新版本, IHostingEnvironment已被弃用并替换为IWebHostEnvironment

public Startup(IWebHostEnvironment webHostEnvironment)
{
    var webRootPath = webHostEnvironment.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\\")))

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:如果这对任何人有用,在 Razor Page cshtml.cs 文件中,这里是获取它的方法:向构造函数添加IHostEnvironment hostEnvironment参数,它将自动注入:

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! PS: IHostEnvironmentMicrosoft.Extensions.Hosting命名空间中,在Microsoft.Extensions.Hosting.Abstractions.dll …… IHostEnvironment一团糟!

如果通过 DI 使用IWebHostEnvironment不适合您,请使用

AppContext.BaseDirectory

Based on Henrique A technique and supports Unit Test contexts as well...基于 Henrique A 技术并支持单元测试上下文......

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

I test and compare on asp.net core 6, I think this can help someone.我在 asp.net 内核 6 上进行测试和比较,我认为这可以帮助某人。

Assume your project location path is D:\Project\Server , if you use linux or mac just replace \ to / .假设您的项目位置路径是D:\Project\Server ,如果您使用 linux 或 mac,只需将\替换为/

var app = builder.Build();
IWebHostEnvironment environment = app.Configuration.Environment;

System.Console.WriteLine(environment.ContentRootPath);
// D:\Project\Server\
System.Console.WriteLine(environment.WebRootPath);
// D:\Project\Server\wwwroot

System.Console.WriteLine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
// D:\Project\Server\bin\Debug\net6.0
System.Console.WriteLine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase));
// file:\D:\Project\Server\bin\Debug\net6.0
System.Console.WriteLine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location));
// D:\Project\Server\bin\Debug\net6.0

System.Console.WriteLine(Directory.GetCurrentDirectory());
// D:\Project\Server
System.Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory);
// D:\Project\Server\bin\Debug\net6.0\
System.Console.WriteLine(AppContext.BaseDirectory);
// D:\Project\Server\bin\Debug\net6.0\

Note: If environment.WebRootPath is empty string, you need create wwwroot folder in root project, then everything work fine.注意:如果environment.WebRootPath为空字符串,您需要在根项目中创建wwwroot文件夹,然后一切正常。

It seems IHostingEnvironment has been replaced by IHostEnvironment (and a few others).似乎 IHostingEnvironment 已被 IHostEnvironment(以及其他一些)取代。 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您可以在 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.编辑 还有一个额外的接口 IWebHostEnvironment 可以在 ASP.NET Core 应用程序中使用。 This is available in the Microsoft.AspNetCore.Hosting namespace.这在 Microsoft.AspNetCore.Hosting 命名空间中可用。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM