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


11

단일 파일 .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

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

답변:


14

나는 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은 완벽합니다. 번들링 된 exe에서 appsettings가 제외되고 게시 작업은 번들링 된 exe와 함께 appsettings 파일을 배치합니다.
Aaron Hudon

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은 어떻게 대상 컴퓨터에 설치됩니까? 나는, 문화를 기반으로 열어야한다는 이미지와 사전 파일이
폴 코헨

@PaulCohen 저는 일반적으로 SCP를 사용하여 게시 된 출력 위치의 모든 파일을 배포합니다. csproj (첫 번째 예)의 변경 사항만으로 기본 루트 컨텐츠 디렉토리를 사용하는 모든 API는 작업 디렉토리에서 파일을 사용할 수 있어야합니다. 추출 된 내용의 실제 경로를 얻으려면 두 번째 예제를 사용해야하는 것처럼 들리므로 전체 경로에서 이미지에 액세스하거나 ~ / ... 경로를 설정하도록 내용 루트를 올바르게 설정하십시오 이미지를 면도기에서 사용할 수 있습니다.
로널드 Swaine

내 배경은 임베디드 응용 프로그램에 있으므로 단일 바이너리는 일반적으로 롬에 구워집니다. 내가 깨달은 것은 일종의 자동 압축 풀림“zip like”파일에서 공유하는 Exe입니다. 내 모든 데이터 파일이 있고 응용 프로그램이 실행될 때 모든 것이 임시로 추출됩니다. 내가 찾은 경우 내 데이터 파일을 찾을 수 있습니다. 또한 데이터가 다른 곳에 VS에서 디버깅 할 수 있도록 논리가 필요하다는 것을 의미합니다.
Paul Cohen

1
현재이 설정이 있으며 파일 찾기를 임의로 중지했습니다.
가는 - 사라

1

내 응용 프로그램은 .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>();
    });
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.