如何获取.NET Core 3单文件应用程序以查找appsettings.json文件?


11

如何配置单文件.Net Core 3.0 Web API应用程序以查找appsettings.json与创建单文件应用程序相同的目录中的文件?

跑步后

dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true

该目录如下所示:

XX/XX/XXXX  XX:XX PM    <DIR>          .
XX/XX/XXXX  XX:XX PM    <DIR>          ..
XX/XX/XXXX  XX:XX PM               134 appsettings.json
XX/XX/XXXX  XX:XX PM        92,899,983 APPNAME.exe
XX/XX/XXXX  XX:XX PM               541 web.config
               3 File(s)     92,900,658 bytes

但是,尝试运行会APPNAME.exe导致以下错误

An exception occurred, System.IO.FileNotFoundException: The configuration file 'appsettings.json' was not found and is not optional. The physical path is 'C:\Users\USERNAME\AppData\Local\Temp\.net\APPNAME\kyl3yc02.5zs\appsettings.json'.
   at Microsoft.Extensions.Configuration.FileConfigurationProvider.HandleException(ExceptionDispatchInfo info)
   at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load(Boolean reload)
   at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load()
   at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers)
   at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.BuildCommonServices(AggregateException& hostingStartupErrors)
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
...

我尝试了类似但截然不同的问题以及其他Stack Overflow问题的解决方案。

我试图将以下内容传递给 SetBasePath()

  • Directory.GetCurrentDirectory()

  • environment.ContentRootPath

  • Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)

每个导致相同的错误。

问题的根源在于PublishSingleFile二进制文件已解压缩并从temp目录运行。

对于此单个文件应用程序,其查找的位置appsettings.json是以下目录:

C:\Users\USERNAME\AppData\Local\Temp\.net\APPNAME\kyl3yc02.5zs

上述所有方法均指向文件解压缩的位置,该位置与运行文件的位置不同。

Answers:


13

我发现在GitHub上的问题,在这里名为PublishSingleFile excluding appsettings not working as expected

那尖锐的另一个问题在这里标题single file publish: AppContext.BaseDirectory doesn't point to apphost directory

解决方案是尝试 Process.GetCurrentProcess().MainModule.FileName

以下代码将应用程序配置为查看运行单可执行应用程序的目录,而不是二进制文件提取到的目录。

config.SetBasePath(GetBasePath());
config.AddJsonFile("appsettings.json", false);

GetBasePath()实施:

private string GetBasePath()
{
    using var processModule = Process.GetCurrentProcess().MainModule;
    return Path.GetDirectoryName(processModule?.FileName);
}

这个答案,加上下面的@ ronald-swaine是完美的。appsettings从捆绑的exe中排除,发布任务将appsettings文件放在捆绑的exe旁边。
亚伦·休顿

8

如果可以在运行时在可执行文件之外使用文件,则可以在csproj中标记要在外部使用的文件。此方法允许在已知位置进行实时更改等。

<ItemGroup>
    <None Include="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <CopyToPublishDirectory>Always</CopyToPublishDirectory>
      <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
    </None>
    <None Include="appsettings.Development.json;appsettings.QA.json;appsettings.Production.json;">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <CopyToPublishDirectory>Always</CopyToPublishDirectory>
      <DependentUpon>appsettings.json</DependentUpon>
      <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
    </None>
  </ItemGroup>

  <ItemGroup>
    <None Include="Views\Test.cshtml">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
    </None>
  </ItemGroup>

如果这是不可接受的,并且必须仅包含一个文件,则在主机设置中将单文件提取的路径作为根路径传递。这允许配置和剃刀(我在其后添加)正常查找其文件。

// when using single file exe, the hosts config loader defaults to GetCurrentDirectory
            // which is where the exe is, not where the bundle (with appsettings) has been extracted.
            // when running in debug (from output folder) there is effectively no difference
            var realPath = Directory.GetParent(System.Reflection.Assembly.GetExecutingAssembly().Location).FullName;

            var host = Host.CreateDefaultBuilder(args).UseContentRoot(realPath);

请注意,要真正制作一个文件而没有PDB,您还需要:

<DebugType>None</DebugType>

您的示例中的Views \ Test.cshtml如何进入目标计算机?我有根据文化需要打开的图像和字典文件
Paul Cohen

@PaulCohen我通常会使用SCP从发布的输出位置部署所有文件。仅通过更改csproj(第一个示例),使用默认根目录目录的所有API都需要在工作目录中提供其文件。听起来您需要使用第二个示例,以获取提取的内容的真实路径,以便您可以从完整路径或通过正确设置内容根目录以使〜/ ...路径访问图像可以在剃须刀中使用图像。
罗纳德·斯威恩

我的背景是嵌入式应用程序,因此通常将一个二进制文件刻录到rom中。我意识到的是,我以某种自我提取的“ zip like”文件形式共享Exe。我所有的数据文件都在其中,当应用程序运行时,所有内容都直接提取到临时文件中。如果发现可以找到我的数据文件。这也意味着我需要一些逻辑,以便可以在VS中的数据不在其他地方进行调试。
保罗·科恩

1
我目前有此安装程序,它随机停止查找文件。
即将于
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.