You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 10:35:56