【问题标题】:Directory.GetCurrentDirectory() doesn't return the correct directory [duplicate]Directory.GetCurrentDirectory() 没有返回正确的目录[重复]
【发布时间】:2019-02-03 23:46:56
【问题描述】:

在我的 ASP.NET Core 2.2 MVC 服务器中,我想添加一个文件夹来存储静态文件。我找到了以下代码来执行此操作:

app.UseStaticFiles(new StaticFileOptions {
    FileProvider = new PhysicalFileProvider(
        Path.Combine(Directory.GetCurrentDirectory(), "StaticFiles")),
    RequestPath = "/StaticFiles"
});

在我的电脑中,该项目位于"C:\Users\MyUsername\source\repos\WebApplication1\WebApplication1",在同一目录下有一个名为“StaticFiles”的文件夹和一个Startup.cs文件,上面的代码就是写在这里的。

但是当我执行代码时出现以下错误:

'System.IO.DirectoryNotFoundException' in Microsoft.Extensions.FileProviders.Physical.dll C:\Program Files\IIS Express\StaticFiles\

Directory.GetCurrentDirectory() 返回 "C:\\Program Files\\IIS Express" 而不是 "C:\Users\MyUsername\source\repos\WebApplication1\WebApplication1"。 我怎样才能得到正确的方向?

【问题讨论】:

  • 嗨 :) 如果您希望它成为应用程序所在的路由,请在调试时从 IIS Express 更改为“YourProjectName”
  • 我认为您应该在项目中包含 StaticFiles 文件夹中的所有文件,并在属性中将 BuildAction 设置为 Content。这样它们就会被包含在安装文件中。
  • @NikolaMarkovinović StaticFiles 在项目文件夹中。 BuildAction 是什么意思?我的 Visual Studio 是西班牙语的,我没有找到任何类似的按钮,那个按钮应该在哪里?
  • 右键单击文件,然后单击Properties。
  • Directory.GetCurrentDirectory() 可以随着程序运行而改变 - 它应该不用于查找相对于应用程序位置的文件。

标签: c# asp.net-core


【解决方案1】:

这是 ASP.NET Core 2.2 中的一个错误,已在GitHub 中报告,Microsoft ASP.NET Core 团队提供了如下解决方案,他们会将此解决方案添加到功能中发布 ASP.NET Core。

编写一个辅助类如下:

public class CurrentDirectoryHelpers
{
    internal const string AspNetCoreModuleDll = "aspnetcorev2_inprocess.dll";

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern IntPtr GetModuleHandle(string lpModuleName);

    [System.Runtime.InteropServices.DllImport(AspNetCoreModuleDll)]
    private static extern int http_get_application_properties(ref IISConfigurationData iiConfigData);

    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    private struct IISConfigurationData
    {
        public IntPtr pNativeApplication;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.BStr)]
        public string pwzFullApplicationPath;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.BStr)]
        public string pwzVirtualApplicationPath;
        public bool fWindowsAuthEnabled;
        public bool fBasicAuthEnabled;
        public bool fAnonymousAuthEnable;
    }

    public static void SetCurrentDirectory()
    {
        try
        {
            // Check if physical path was provided by ANCM
            var sitePhysicalPath = Environment.GetEnvironmentVariable("ASPNETCORE_IIS_PHYSICAL_PATH");
            if (string.IsNullOrEmpty(sitePhysicalPath))
            {
                // Skip if not running ANCM InProcess
                if (GetModuleHandle(AspNetCoreModuleDll) == IntPtr.Zero)
                {
                    return;
                }

                IISConfigurationData configurationData = default(IISConfigurationData);
                if (http_get_application_properties(ref configurationData) != 0)
                {
                    return;
                }

                sitePhysicalPath = configurationData.pwzFullApplicationPath;
            }

            Environment.CurrentDirectory = sitePhysicalPath;
        }
        catch
        {
            // ignore
        }
    }
}

然后在你的代码中调用SetCurrentDirectory()方法如下:

app.UseStaticFiles(new StaticFileOptions {
    FileProvider = new PhysicalFileProvider(

        CurrentDirectoryHelpers.SetCurrentDirectory(); // call it here

        Path.Combine(Directory.GetCurrentDirectory(), "StaticFiles")),
    RequestPath = "/StaticFiles"
});

现在一切都应该正常了!

【讨论】:

  • 谢谢。我不想听起来很悲观,但是,您的代码比Jonas Tuemand Møller 答案有什么优势。他的代码有效,只有 1 行。你的代码有......还有几行。无论如何,mjwills 在 cmets 中就我的问题表示,在任何情况下都不应使用 Directory.GetCurrentDirectory() 来获取路径,因为它可以随着程序的运行而改变。但是感谢您指出错误。
  • @EnderLook 可能是Jonas Tuemand Møller,当您在ASP.NET Core 2.2 中使用InProcess 托管模型时,方法将不起作用。正如 Microsoft ASP.NET Core 所建议的那样,使用此解决方案是最安全的方式。
  • 好吧,我不知道InProcess 是什么,但听起来很重要:)。我用这个。谢谢! (我还不接受它,因为通常的做法是至少等待 24 小时才能接受答案)。
  • 哈哈! :) 没问题!还有一点需要注意的是,它可以在调试模式下工作,而无需在 .csproj 文件中添加这个<ItemGroup><Content Include="StaticFiles\**"><CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory></Content></ItemGroup>
  • 我知道,但是我注意到当我按“发布”时,VS 不会复制发布版本中的“静态文件”(也不是它的内容)。通过尝试一个错误,我发现将该行添加到.csproj 文件夹已复制到版本中。
【解决方案2】:

IHostingEnvironment 接口提供有关环境的信息,包括基本路径。您可以使用依赖注入获取实例。

public class Startup
{
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        // env.ContentRootPath;
    }
}

【讨论】:

    【解决方案3】:

    您的应用程序的默认工作目录似乎指向 IIS Express 的工作目录

    首先尝试使用HostingEnvironment从Program.cs设置基本路径

      var builder = new ConfigurationBuilder()
          .SetBasePath(env.ContentRootPath)
    

    如果这不起作用,最简单的选择是从launchSettings.json 设置 IIS Express 启动配置文件的工作目录。为此,

    • 右键单击您的项目并选择属性。
    • 进入调试状态
    • 选择要使用的配置文件
    • 进入Working Directory 文本框并设置您的工作目录

    注意:这不会影响您的构建,它只是一个调试配置。


    new HostBuilder()
        .CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((context, builder) =>
        {               
             builder
                .SetBasePath(context.HostingEnvironment.ContentRootPath)
    

    【讨论】:

    • env 不存在,这是什么意思?还有,我现在用的是CreateDefaultBuilder(),可以用SetBasePath吗?
    • 请检查我的编辑
    猜你喜欢
    • 1970-01-01
    • 2017-05-16
    • 2015-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-02
    • 2012-08-07
    • 2011-10-18
    相关资源
    最近更新 更多