.NET Core 3.1 Windows服务始终在System32查找配置文件求助
.NET Core 3.1 Windows服务找不到appsettings.json的解决办法
问题概述
基于.NET Core 3.1开发的Windows服务,以服务形式运行时会默认在C:\Windows\System32目录下查找appsettings.json配置文件,触发文件未找到异常。命令行直接运行程序正常,但转为Windows服务后就失败,且当前无法升级.NET框架版本。
事件查看器错误日志
CoreCLR Version: 4.700.19.56402 .NET Core Version: 3.1.0 Description: The process was terminated due to an unhandled exception. Exception Info: System.IO.FileNotFoundException: The configuration file 'appsettings.json' was not found and is not optional. The physical path is 'C:\Windows\system32\appsettings.json'.
相关代码
public static void Main(string[] args) { var logger = Common.Logging.LogManager.GetNonDILogger<Program>(); try { logger.LogDebug("Initialize worker"); var host = CreateHostBuilder(args).Build(); host.Run(); logger.LogInformation($"Stopped worker"); } catch (OperationCanceledException) { logger.LogInformation($"Stopped worker because of cancelation"); } catch (Exception ex) { logger.LogError(ex, "Stopped worker because of exception"); throw; } finally { NLog.LogManager.Shutdown(); } } public static IHostBuilder CreateHostBuilder(string[] args) { return Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((ctx, cfg) => cfg.AddSettings(ctx.HostingEnvironment, args)) .ConfigureLogging(SetupLogging) .ConfigureServices((ctx, sc) => ConfigureServices(sc, ctx.Configuration)) .UseWindowsService(); } private static void SetupLogging(HostBuilderContext ctx, ILoggingBuilder builder) { if (ctx == null) { throw new ArgumentNullException(nameof(ctx)); } if (builder == null) { throw new ArgumentNullException(nameof(builder)); } _ = builder.ClearProviders() .SetMinimumLevel(LogLevel.Trace) .AddConfiguration(ctx.Configuration.GetSection("Nlog")) .AddNLog(); // Add NLog to the logging pipeline } public static IConfigurationBuilder AddSettings(this IConfigurationBuilder builder, IHostEnvironment env, string[] args) { if (env == null) { throw new ArgumentNullException(nameof(env)); } if (args == null) { throw new ArgumentNullException(nameof(args)); } _ = builder .SetBasePath("C:\\Program Files\\My.Worker"); //.SetBasePath(env.ContentRootPath) //.SetBasePath(System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)) //.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) //.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true) //.AddEnvironmentVariables(); //if (args != null) { // _ = builder.AddCommandLine(args); //} //_ = builder.AddSubstitution(); return builder; }
已尝试的解决方法
- 在
AddSettings方法中尝试使用env.ContentRootPath、Assembly.GetExecutingAssembly().Location获取路径作为BasePath,但服务运行时仍无效 - 尝试通过
New-Service命令指定--contentRoot参数创建服务:
New-Service -Name "My.Worker" -BinaryPathName "C:\src\src\My.Worker\bin\Debug\netcoreapp3.1\My.Worker.exe" -DisplayName "My Worker" -StartupType Automatic New-Service -Name "My.Worker" -BinaryPathName "C:\src\src\My.Worker\bin\Debug\netcoreapp3.1\My.Worker.exe --contentRoot ""C:\src\src\My.Worker\bin\Debug\netcoreapp3.1""" -DisplayName "My Worker" -StartupType Automatic
可行的解决办法
1. 修复配置加载逻辑,确保BasePath和配置文件加载完整
当前AddSettings方法仅设置了BasePath,但未添加appsettings.json的加载代码,同时需要确保BasePath获取不受服务工作目录影响:
public static IConfigurationBuilder AddSettings(this IConfigurationBuilder builder, IHostEnvironment env, string[] args) { if (env == null) { throw new ArgumentNullException(nameof(env)); } if (args == null) { throw new ArgumentNullException(nameof(args)); } // 获取程序集的实际执行目录,不受服务默认工作目录干扰 var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); _ = builder .SetBasePath(assemblyDir) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables(); if (args?.Length > 0) { _ = builder.AddCommandLine(args); } // 保留AddSubstitution(如果业务需要) //_ = builder.AddSubstitution(); return builder; }
2. 提前设置Host的ContentRoot目录
在创建HostBuilder时,先通过UseContentRoot指定程序集目录,避免后续配置读取时使用默认的系统目录:
public static IHostBuilder CreateHostBuilder(string[] args) { var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); return Host.CreateDefaultBuilder(args) .UseContentRoot(assemblyDir) // 优先设置内容根目录 .ConfigureAppConfiguration((ctx, cfg) => cfg.AddSettings(ctx.HostingEnvironment, args)) .ConfigureLogging(SetupLogging) .ConfigureServices((ctx, sc) => ConfigureServices(sc, ctx.Configuration)) .UseWindowsService(); }
3. 修正服务安装命令的引号格式
之前的New-Service命令中参数引号格式错误,正确格式需要将整个命令(包括exe路径和参数)用双引号包裹:
New-Service -Name "My.Worker" -BinaryPathName '"C:\src\src\My.Worker\bin\Debug\netcoreapp3.1\My.Worker.exe" --contentRoot "C:\src\src\My.Worker\bin\Debug\netcoreapp3.1"' -DisplayName "My Worker" -StartupType Automatic
4. 确保配置文件被复制到输出目录
在项目属性中,设置appsettings.json的复制到输出目录为「始终复制」或「如果较新则复制」,确保文件随程序一起发布到目标目录。
内容的提问来源于stack exchange,提问作者Thad
相关产品推荐
相关产品推荐

