.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()
将获取系统位置,而不是应用程序部署的位置。
我创建了一个 .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()
将获取系统位置,而不是应用程序部署的位置。