Я помещаю информацию о каталоге журнала и файле журнала в свой класс параметров. Этот класс параметров также имеет валидатор, реализующий интерфейс IValidateOptions. В этот валидатор вводится экземпляр средства ведения журнала для регистрации ошибок проверки, если они возникли.
Провайдеру средства ведения журнала файлов необходимо внедрить монитор параметров, чтобы получить доступ к конфигурациям каталога и файлов.
К сожалению, при запуске приложения возникает исключение.
System.AggregateException: «Некоторые службы не могут работать
создан'
с содержимым
Ошибка при проверке дескриптора службы ' ServiceType:
Microsoft.Extensions.Hosting.IHostApplicationLifetime Срок действия:
Singleton ImplementationType:
Microsoft.Extensions.Hosting.Internal.ApplicationLifetime': Для службы обнаружена циклическая
зависимость введите
'Microsoft.Extensions.Logging.ILoggerFactory'.
Microsoft.Extensions.Hosting.IHostApplicationLifetime(Microsoft.Extensions.Hosting.Internal.ApplicationLifetime)
-> Microsoft.Extensions.Logging.ILogger (Microsoft.Extensions.Logging.Logger)
-> Microsoft.Extensions.Logging.ILoggerFactory(Microsoft.Extensions.Logging .LoggerFactory)
-> System.Collections.Generic.IEnumerable
-> Microsoft.Extensions.Logging.ILoggerProvider(Ajifsdjfijgsidjfijsdifjisd.FileLoggerProvider)
-> Microsoft .Extensions.Options.IOptionsMonitor(Microsoft.Extensions.Options.OptionsMonitor)
-> Microsoft.Extensions.Options.IOptionsFactory(Microsoft.Extensions.Options. OptionsFactory)
-> System.Collections.Generic.IEnumerable
-> Microsoft.Extensions.Options.IValidateOptions(MyLib.MyOptionsValidator)
-> Microsoft.Extensions.Logging.ILogger(Microsoft.Extensions.Logging.Logger)
-> Microsoft.Extensions.Logging.ILoggerFactory
Это имеет смысл, поскольку при внедрении нового экземпляра средства ведения журнала это человеку вводят варианты. И это запустит валидатор, который введет новый экземпляр регистратора. И все начинается заново.
Logger => Параметры => Валидатор => Регистратор => Параметры => Валидатор =>
Logger => Параметры => Валидатор => ...
Я не знаю, как решить эту проблему, поскольку моему регистратору файлов необходим доступ к параметрам конфигурации и мой валидатор параметров должен регистрировать ошибки проверки.
Есть идеи?
Если вы хотите получить обзор приложения, вот что я сделал, чтобы воспроизвести его:
- Создайте новый проект .NET Core Worker
- Наверх в файл .csproj и добавьте в первую группу элементов, чтобы получить доступ к Kestrel и веб-материалам.
- Я добавить библиотеку MyLib в проект и ссылаться на нее в основном проекте
- В библиотеке я создаю класс параметров, содержащий информацию для регистратора файлов
Код: Выделить всё
public class MyOptions
{
public string DirectoryPath { get; set; }
public string FileName { get; set; }
}
- Я также добавляю простой пример средства проверки параметров, в котором используется экземпляр журнала
Код: Выделить всё
public class MyOptionsValidator : IValidateOptions
{
private readonly ILogger logger;
public MyOptionsValidator(ILogger logger)
{
this.logger = logger;
}
public ValidateOptionsResult Validate(string name, MyOptions myOptions)
{
if (string.IsNullOrEmpty(myOptions.DirectoryPath) || string.IsNullOrEmpty(myOptions.FileName))
{
logger.LogWarning("Invalid");
return ValidateOptionsResult.Fail("Invalid");
}
return ValidateOptionsResult.Success;
}
}
- Я добавляю параметры в файл appsettings.json
- Я добавляю параметры в файл appsettings.json
- Я добавляю параметры в файл appsettings.json
- Я добавляю параметры в файл appsettings.json
- Я добавляю параметры в файл appsettings.json
- Я добавляю параметры в файл appsettings.json
- Я добавляю параметры в файл appsettings.json.
- р>
В библиотеке я расширяю коллекцию сервисов для регистрации вариантов проверки
Код: Выделить всё
"MyOptions": { "DirectoryPath": "C:\\Logs", "FileName": "log.log" }
Код: Выделить всё
public static class IServiceCollectionExtensions
{
public static IServiceCollection AddMyLib(this IServiceCollection services) =>
services.AddSingleton();
}
- В основном проекте я настраиваю часть журналирования. Сначала я создаю новый файловый регистратор. Поскольку этот сервис не может быть «обычным» и не будет добавлен в контейнер DI, я просто ожидаю, что необходимые параметры будут в конструкторе
Код: Выделить всё
internal class FileLogger : ILogger
{
private readonly string fullLogFilePath;
public FileLogger(string logDirectoryPath, string logFileName)
{
if (!Directory.Exists(logDirectoryPath))
Directory.CreateDirectory(logDirectoryPath);
fullLogFilePath = Path.Combine(logDirectoryPath, logFileName);
}
public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter)
{
if (!IsEnabled(logLevel))
return;
using StreamWriter streamWriter = new StreamWriter(fullLogFilePath, true);
streamWriter.WriteLine($"[{DateTime.Now}] [{logLevel}] {formatter(state, exception)} {exception?.StackTrace}");
}
public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;
public IDisposable BeginScope(TState state) => null;
}
- Чтобы обслуживать этот регистратор, я добавил поставщика
Код: Выделить всё
internal class FileLoggerProvider : ILoggerProvider
{
private readonly IOptionsMonitor myOptionsMonitor;
public FileLoggerProvider(IOptionsMonitor myOptionsMonitor)
{
this.myOptionsMonitor = myOptionsMonitor;
}
public void Dispose()
{
}
public ILogger CreateLogger(string categoryName)
{
MyOptions myOptions = myOptionsMonitor.CurrentValue;
return new FileLogger(myOptions.DirectoryPath, myOptions.FileName);
}
}
- и расширьте построитель журналов, добавив файловый регистратор
- и расширьте построитель журналов, добавив файловый регистратор
- расширьте построитель журналов, добавив файловый регистратор
- р>
Как и в проекте веб-API, я добавил файл запуска для настройки всех параметров и служб.
Код: Выделить всё
public static class ILoggingBuilderExtensions { public static void AddFileLogger(this ILoggingBuilder loggingBuilder) { loggingBuilder.Services.AddSingleton(); } }
< /ul>
.Код: Выделить всё
internal class Startup { private readonly IConfiguration configuration; public Startup(IConfiguration configuration) { this.configuration = configuration; } public void ConfigureServices(IServiceCollection services) { services.AddMyLib(); IConfigurationSection myOptionsSection = configuration.GetSection("MyOptions"); services.Configure(myOptionsSection); } public void Configure(IApplicationBuilder applicationBuilder) { } }
- В последней части я обновил файл программы до этого
Код: Выделить всё
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(loggingBuilder =>
{
loggingBuilder
.ClearProviders()
.AddConsole()
.AddEventLog()
.AddFileLogger();
})
.ConfigureWebHostDefaults(webHostBuilder =>
{
webHostBuilder.UseKestrel().UseStartup();
})
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService();
});
}
- Вы должны получить исключение System.AggregateException из-за циклической зависимости
Подробнее здесь: https://stackoverflow.com/questions/646 ... -options-w