[c#] .NET Core 3 단일 파일 앱에서 appsettings.json 파일을 찾으려면 어떻게해야합니까?

단일 파일 .Net Core 3.0 웹 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

위의 모든 방법은 파일이 압축 해제 된 위치를 가리키며, 이는 실행 위치와 다릅니다.



답변

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


답변

실행 파일 외부에서 런타임에 파일을 사용하는 것이 좋다면 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>


답변

내 응용 프로그램은 .NET Core 3.1에 있으며 단일 파일로 게시되며 Windows 서비스로 실행됩니다 (문제에 영향을 줄 수도 있고받지 않을 수도 있음).

Process.GetCurrentProcess().MainModule.FileName컨텐츠 루트로 제안 된 솔루션 은 저에게 효과적이지만 컨텐츠 루트를 올바른 위치에 설정 한 경우에만 가능합니다.

이것은 작동합니다 :

Host.CreateDefaultBuilder(args)
    .UseWindowsService()
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseContentRoot(...);
        webBuilder.UseStartup<Startup>();
    });

작동하지 않습니다.

Host.CreateDefaultBuilder(args)
    .UseWindowsService()
    .UseContentRoot(...)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
    });


답변