.NET Core 工作器异常:值不能为空。参数名称 connectionString

.NET Core worker exception: Value cannot be null. Parameter name connectionString

我创建了一个 .net 核心工作器并将其安装为服务。我还在 worker 中实现了一个 Serilog 记录器。记录工作人员何时启动和关闭。当 运行 我的工作人员处于调试模式时,它完美地记录在 MSSQL 服务器日志 table 中。但是,当我以发布模式发布工作人员并从服务启动工作人员时,它不会记录任何内容。它抛出异常:值不能为空。参数名称连接字符串。我该如何解决这个问题?

appsettings.json:

{
  "Serilog": {
    "Using": [ "Serilog.Sinks.MSSqlServer" ],
    "MinimumLevel": "Information",
    "WriteTo": [
      {
        "Name": "MSSqlServer",
        "Args": {
          "connectionString": "Server=localhost; Initial Catalog=context; User ID=ct; Password=ct",
          "tableName": "Log"
        }
      }
    ]
  },

  "AllowedHosts": "*",

  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost; Initial Catalog=context; User ID=ct; Password=ct"
  },

  "EnyimMemcached": {
    "Servers": [
      {
        "Address": "127.0.0.1",
        "Port": 11211
      }
    ]
  }
}

Worker.Program.cs

public class Program 

{
        public static readonly stringenvironmentName=Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production";

        public static readonly IConfiguration configuration = new ConfigurationBuilder()
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                    .AddJsonFile($"appsettings.{environmentName}.json", optional: true)
                .Build();

        public static void Main(string[] args)
        {
            try
            {
                var iWebHost = CreateHostBuilder(args).Build();
                
                var logger = new LoggerConfiguration()
                    .Enrich.FromLogContext()
                    .ReadFrom.Configuration(configuration)
                    .CreateLogger();

                Log.Logger = logger;
                iWebHost.Run();
            }
            catch (Exception exception)
            {
                Log.Fatal(exception, "Error starting the service");
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<GameWorker>();
                    services.AddDbContextPool<IqSoftLiveCasinoContext>(optionsBuilder =>
                    {
                        optionsBuilder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"));
                    });
                    services.AddEnyimMemcached(options => configuration.GetSection("EnyimMemcached").Bind(options));
                    services.AddScoped<IUnitOfWork, UnitOfWork>();
                    services.AddScoped<ICacheProvider, CacheProvider>();
                })
                .UseSerilog()
                .UseWindowsService();
    }

GameWorker.cs

public class GameWorker : BackgroundService
    {
        private readonly ILogger<GameWorker> _logger;
        public IServiceScopeFactory _serviceProvider;

        public GameWorker(ILogger<GameWorker> logger, IServiceScopeFactory serviceProvider)
        {
            _logger = logger;
            _serviceProvider = serviceProvider;
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("GameWorker started at {time}", DateTime.UtcNow);
            return base.StartAsync(cancellationToken);
        }

        public override Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("GameWorker stopped at {time}", DateTime.UtcNow);
            return base.StopAsync(cancellationToken);
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation($"Worker running at: {DateTimeOffset.Now}");
                await Task.Delay(10000, stoppingToken);
            }
        }

问题在这一行:

.SetBasePath(Directory.GetCurrentDirectory())

您需要以不同的方式传递目录,您可以尝试使用如下方式:

var uri = new UriBuilder(Assembly.GetExecutingAssembly().CodeBase);
var path = Uri.UnescapeDataString(uri.Path);
.SetBasePath(Path.GetDirectoryName(path))

那是因为当你 运行 它通过 VS 时,它会得到你 运行 从中获取它的确切上下文,但是当它 运行 作为服务时 Directory.GetCurrentDirectory() 将获取系统位置,而不是应用程序部署的位置。