Проблемы с чтением appsettings.(environment).json в синглтоне .NET Core 8

Я создаю службу 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.

Как мне получить доступ к своим настройкам в синглтоне? Большое спасибо

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Для настроек следует использовать шаблон Параметры. Вы их зарегистрировали нормально, но чтобы получить их через DI, вам придется обернуть их в IOptions:

public PlannedOutageService(IOptions<SettingsConfig> appSettings) 
{
   // access settings via appSettings.Value, check for NULL if necessary
}

Вторая проблема не связана с настройками. Вы пытаетесь получить доступ к полю экземпляра статическим методом, но это не сработает. Это статический контекст, поэтому вы можете получить доступ только к статическим полям, поскольку не существует ни одного доступного экземпляра, из которого вы могли бы скрыть эти данные.

ОБНОВЛЯТЬ: Вы сказали, что хотите получить доступ к своим настройкам в статическом контексте. Ну, так это не сработает, потому что если вы вводите данные через DI, значение должно храниться в поле экземпляра. Итак, здесь у вас есть два варианта:

  1. Внедрение пользовательского метода, т. е. просто передайте свои настройки в метод:

    общедоступный статический MyMestod (SettingsConfig appSettings)

  2. Даже лучший способ: не используйте статический класс для реализации синглтона, если вам нужны переменные экземпляра и DI. Есть лучший способ добиться того, чтобы существовал только один экземпляр класса. Просто создайте обычную пару класс-интерфейс и зарегистрируйте ее как синглтон:

    Services.AddSingleton<IPlannedOutageService, PlannedOutageService>();

Другие вопросы по теме