단일 파일 .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>();
});