Простой инжектор: зарегистрируйте ILogger путем использование ILoggerFactory.Креатологгер ()
Я работаю с проектом, который использует простой инжектор инжектор зависимостей. С другой стороны, этот проект использует Microsoft.Увеличение.Ведение журнала для регистрации событий, происходящих в определенных классах.
моя техническая проблема довольно проста в объяснении.
Я хочу зарегистрировать в своем DI ILogger независимо от класса T, который вызывается, но МНЕ НУЖНО сделать это из моего ILoggerFactory.CreateLogger<T>()
метод, потому что это получает конфигурации регистратора через Microsoft.Extensions.Configuration
.
мне нужно использовать что-то вроде этого, чтобы создать экземпляр моего регистратора:
private Microsoft.Extensions.Logging.ILogger CreateLogger<T>()
{
var factory = this.ResolveService<ILoggerFactory>();
var logger = factory.CreateLogger<T>();
return logger;
}
я смог достигнуть впрыски путем делать:
Container.Register(typeof(ILogger<>), typeof(Logger<>));
и это позволяет нам решить что-то вроде:
public class SomeApiController : ApiController
{
public SomeApiController(ILogger<SomeApiController> logger)
{
//logger is well instantiated, but doesn't got the configuration
logger.LogInformation("test log.");
}
}
но, как я уже сказал, это делает это, не проходя через конфигурацию, полученную из Microsoft.Extensions.Logging.ILoggerFactory
класс, так что это не полезно.
есть ли способ зарегистрироваться
ILogger<T>
С помощью myCreateLogger<T>
?
2 ответов
способ сделать это с помощью простого инжектора-указать общий прокси-класс, который делегирует вызов ILoggerFactory
.
это, однако, вызывает проблему при использовании Microsoft.Увеличение.Ведение журнала, потому что это ILogger<T>
абстракция-это одна большая Принцип Разделения Интерфейса нарушение. Нарушения ISP проблематичны, потому что они затрудняют создание (среди прочего) прокси-классов. Но вы должны воздерживаться от использования этой абстракции непосредственно в ваши компоненты приложения любым способом, как предписано Принцип Инверсии Зависимостей.
поскольку абстракции должны определяться самим приложением, это в основном означает, что вам нужно определить свой собственный абстракция регистратор и поверх этого вы строите адаптер, как описано здесь. Вы можете просто вывести свой универсальный адаптер из описанного MicrosoftLoggingAdapter
следующим образом:
public sealed class MicrosoftLoggingAdapter<T> : MicrosoftLoggingAdapter
{
public MicrosoftLoggingAdapter(ILoggerFactory factory)
: base(factory.CreateLogger<T>()) { }
}
используя этот универсальный адаптер, вы можете настроить простой инжектор следующим образом:
container.RegisterSingleton<ILoggerFactory>(factory);
container.RegisterConditional(
typeof(MyApplication.Abstractions.ILogger),
c => typeof(MicrosoftLoggingAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
в случае, если создание собственной абстракции не является (пока) вариантом, ваш второй лучший выбор-переопределить поведение инъекции зависимостей простого инжектора со следующей Microsoft.Увеличение.Класс ведения журнала:
class MsContextualLoggerInjectionBehavior : IDependencyInjectionBehavior
{
private readonly ILoggerFactory factory;
private readonly IDependencyInjectionBehavior original;
private readonly Container container;
public MsContextualLoggerInjectionBehavior(
ILoggerFactory factory, Container container)
{
this.factory = factory;
this.original = container.Options.DependencyInjectionBehavior;
this.container = container;
}
public void Verify(InjectionConsumerInfo consumer) => original.Verify(consumer);
public InstanceProducer GetInstanceProducer(InjectionConsumerInfo i, bool t) =>
i.Target.TargetType == typeof(ILogger)
? GetLoggerInstanceProducer(i.ImplementationType)
: original.GetInstanceProducer(i, t);
private InstanceProducer<ILogger> GetLoggerInstanceProducer(Type type) =>
Lifestyle.Singleton.CreateProducer(() => factory.CreateLogger(type), container);
}
вы можете заменить исходное поведение следующим образом:
container.Options.DependencyInjectionBehavior =
new MsContextualLoggerInjectionBehavior(loggingFactory, container);
основываясь на решении Стивена, я публикую свой ответ, чтобы помочь кому-либо еще:
private void RegisterServices()
{
Container.Register(ConfigureLogger, Lifestyle.Singleton);
Container.Register(typeof(ILogger<>), typeof(LoggingAdapter<>));
}
private ILoggerFactory ConfigureLogger()
{
LoggerFactory factory = new LoggerFactory();
var config = new ConfigurationBuilder()
.AddJsonFile("logging.json")
.Build();
//serilog provider configuration
var log = new LoggerConfiguration()
//.ReadFrom.Configuration(config)
.WriteTo
.RollingFile(ConfigSettings.LogsPath)
.CreateLogger();
factory.AddSerilog(log);
return factory;
}
public class LoggingAdapter<T> : ILogger<T>
{
private readonly Microsoft.Extensions.Logging.ILogger adaptee;
public LoggingAdapter(ILoggerFactory factory)
{
adaptee = factory.CreateLogger<T>();
}
public IDisposable BeginScope<TState>(TState state)
{
return adaptee.BeginScope(state);
}
public bool IsEnabled(LogLevel logLevel)
{
return adaptee.IsEnabled(logLevel);
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
adaptee.Log(logLevel, eventId, state, exception, formatter);
}
}
Как вы можете видеть, мое решение использует Serilog в качестве поставщика для входа в Microsoft.Extensions.Logging
.
надеюсь, что это помогает!