web-dev-qa-db-ja.com

.NET Core 3シングルファイルアプリを取得してappsettings.jsonファイルを見つけるにはどうすればよいですか?

単一ファイル.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()
...
_

似ているが明確な質問 からの解決策、および他のスタックオーバーフローの質問を試しました。

以下をSetBasePath()に渡そうとしました

  • Directory.GetCurrentDirectory()

  • _environment.ContentRootPath_

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

それぞれが同じエラーにつながりました。

問題の根本は、PublishSingleFileバイナリが解凍され、tempディレクトリから実行されることです。

この単一ファイルアプリの場合、_appsettings.json_が探していた場所は次のディレクトリでした。

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

上記のすべての方法は、ファイルの解凍先を指します。これは、実行された場所とは異なります。

11
Jason Yandell

GitHub here に_PublishSingleFile excluding appsettings not working as expected_というタイトルの問題が見つかりました。

それは別の問題を指摘しました here _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);
}
_
12
Jason Yandell

実行可能ファイルの外で実行時にファイルを使用することに問題がない場合は、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>

これが受け入れられず、ファイルが1つだけでなければならない場合は、ホストセットアップで、単一ファイル抽出パスをルートパスとして渡します。これにより、構成とかみそり(後で追加)が通常どおりファイルを見つけることができます。

// 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>
8
Ronald Swaine