Я создаю службу Windows на C# в .NET Core 8. Это моя первая попытка. Сервис работает, но теперь я хочу удалить некоторые жестко запрограммированные элементы и перенести настройки в свой appsettings.json
файл.
Я начал с нескольких настроек.
Мой appsettings.Development.json
имеет следующее содержание:
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
"PlannedOutageConn": "Data Source=localhost;Initial Catalog=planned_outage;Persist Security Info=True;User ID=User;Password=password;Trust Server Certificate=True"
},
"Settings": {
"corsOrigin": "http://Server1",
"plannedOutageWebService": "https://localhost:7400/api/triview",
"verboseLogging": true
}
У меня есть класс SettingsConfig
:
namespace PlannedOutageWindowsSvc.Models
{
/// <summary>
/// A class representing the various app configurations found in appsettings.{environment}.json
/// </summary>
public class SettingsConfig
{
/// <summary>
/// The origin host e.g. http://localhost or https://Server1
/// </summary>
public string corsOrigin { get; set; } = "";
/// <summary>
/// Api endpoint for Planned Outage Web Service
/// </summary>
public string plannedOutageWebService { get; set; } = "";
/// <summary>
/// Dictates if verbose logging is on or off (boolean)
/// </summary>
public bool verboseLogging { get; set; }
}
}
В моем program.cs
у меня есть следующее:
using App.WindowsService;
using Microsoft.EntityFrameworkCore;
using PlannedOutageWindowsSvc.Models;
using NLog;
using NLog.Web;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddWindowsService(options =>
{
options.ServiceName = "PlannedOutageWinSvc";
});
var env = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile($"appsettings.json", false, true)
.AddJsonFile($"appsettings.{env}.json", true, true)
.AddEnvironmentVariables()
.Build();
// Early init of NLog to allow startup and exception logging, before host is built
var mlogger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
mlogger.Warn("PlannedOutageWindowsService is being initiated");
try
{
//DB connection/context
builder.Services.AddDbContext<planned_outageContext>(
options => options.UseSqlServer(builder.Configuration.GetConnectionString("PlannedOutageConn")));
builder.Services.Configure<SettingsConfig>(config.GetSection("Settings"));
builder.Services.AddHostedService<WindowsBackgroundService>();
builder.Services.AddSingleton<PlannedOutageService>();
IHost host = builder.Build();
host.Run();
}
catch (Exception ex)
{
// NLog: catch setup errors
mlogger.Error(ex, "PlannedOutageWindowsService stopped because of exception");
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
Теперь я хочу получить доступ к своим настройкам из appSettings.{env}.json
в моем PlannedOutageService.cs
одноэлементном классе:
using PlannedOutageWindowsSvc.Models;
using System.Text.Json;
namespace App.WindowsService
{
public class PlannedOutageService()
{
private SettingsConfig svcSettings;
public PlannedOutageService(SettingsConfig? appSettings) //ERROR CS8863
{
svcSettings = appSettings;
}
public static async Task ProcessTriViewMessages()
{
//THIS IS WHERE I WANT TO ACCESS THE SETTINGS VALUES
string triviewUrl = svcSetting.plannedOutagesWebService; //ERROR CS0120
// ..... other code removed
}
}
}
Приведенный выше код приводит к двум ошибкам, которые я не могу устранить:
CS8862 Конструктор, объявленный в типе со списком параметров, должен иметь инициализатор конструктора this.
CS0120 Требуется ссылка на объект для нестатического поля, метода или свойства PlannedOutageService.svcSettings.
Как мне получить доступ к своим настройкам в синглтоне? Большое спасибо
Для настроек следует использовать шаблон Параметры. Вы их зарегистрировали нормально, но чтобы получить их через DI, вам придется обернуть их в IOptions:
public PlannedOutageService(IOptions<SettingsConfig> appSettings)
{
// access settings via appSettings.Value, check for NULL if necessary
}
Вторая проблема не связана с настройками. Вы пытаетесь получить доступ к полю экземпляра статическим методом, но это не сработает. Это статический контекст, поэтому вы можете получить доступ только к статическим полям, поскольку не существует ни одного доступного экземпляра, из которого вы могли бы скрыть эти данные.
ОБНОВЛЯТЬ: Вы сказали, что хотите получить доступ к своим настройкам в статическом контексте. Ну, так это не сработает, потому что если вы вводите данные через DI, значение должно храниться в поле экземпляра. Итак, здесь у вас есть два варианта:
Внедрение пользовательского метода, т. е. просто передайте свои настройки в метод:
общедоступный статический MyMestod (SettingsConfig appSettings)
Даже лучший способ: не используйте статический класс для реализации синглтона, если вам нужны переменные экземпляра и DI. Есть лучший способ добиться того, чтобы существовал только один экземпляр класса. Просто создайте обычную пару класс-интерфейс и зарегистрируйте ее как синглтон:
Services.AddSingleton<IPlannedOutageService, PlannedOutageService>();