SimpleInjectorを依存性注入器として利用するプロジェクトに取り組んでいます。一方、このプロジェクトでは、特定のクラスで発生するイベントをログに記録するためにMicrosoft.Extensions.Loggingを使用します。
私の技術的な問題は非常に簡単に説明できます。呼び出されているクラスTとは無関係にILoggerをDIに登録したいのですが、I DO NEEDILoggerFactory.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>
を使用してCreateLogger<T>
を登録する方法はありますか?
[〜#〜] tldr [〜#〜];次の登録を使用します。
_container.RegisterInstance<ILoggerFactory>(loggerFactory);
container.RegisterSingleton(typeof(ILogger<>), typeof(Logger<>));
_
CreateLogger<T>()
メソッドはILoggerFactory
の拡張メソッドであり、次のように実装されます( LoggerFactoryExtensions によって)。
_public static ILogger<T> CreateLogger<T>(this ILoggerFactory factory)
{
return new Logger<T>(factory);
}
_
_CreateLogger<T>
_は、工場への供給中に新しい_Logger<T>
_を作成するだけです。つまり、_CreateLogger<T>
_を呼び出すと、_Logger<T>
_を手動で作成するか、SimpleInjectorに実行させるのと同じ効果があります。
したがって、与えられた登録はあなたの質問を解決するはずです:
_container.RegisterInstance<ILoggerFactory>(loggerFactory);
container.RegisterSingleton(typeof(ILogger<>), typeof(Logger<>));
_
ただし、アプリケーションコンポーネントを_ILogger<T>
_の依存関係に依存させるのではなく、代わりにILogger
に依存させることをお勧めします。これにより、コードが単純になり、テストが容易になり、エラーが発生しにくくなります。 Simple Injectorに、正しい_Logger<T>
_がまだ注入されていることを確認させることができます。
_container.RegisterConditional(
typeof(ILogger),
c => typeof(Logger<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
_ => true);
_
これにより、すべてのアプリケーションコンポーネントが独自の_Logger<T>
_インスタンスを取得します。ここで、T
はロガーが挿入されるコンポーネントのタイプです。 ILogger
に依存する次のクラスを例にとってみましょう。
_public class ComponentA : IService
{
public ComponentA(ILogger logger) { ... }
}
_
上記の登録により、ComponentA
に依存し、_Logger<ComponentA>
_には依存しない場合でも、ILogger
に_ILogger<T>
_が注入されます。
ここで読むのをやめるか、もっとSOLIDソリューションに興味があるなら、読み続けることができます。
アプリケーションコンポーネントをフレームワークで定義されたILogger
抽象化に依存させる代わりに、 依存性逆転の原則 (DIP)で規定されているように、アプリケーション固有のロガー抽象化を定義することもできます。
DIPは、抽象化はアプリケーション自体によって定義される必要があると述べています。つまり、独自の logger抽象化 を定義し、その上に、説明されているように ここ のようにアダプターを構築します。次のように、説明されているMicrosoftLoggingAdapter
から汎用アダプターを簡単に導出できます。
_public sealed class MicrosoftLoggingAdapter<T> : MicrosoftLoggingAdapter
{
public MicrosoftLoggingAdapter(ILoggerFactory factory)
: base(factory.CreateLogger<T>()) { }
}
_
この汎用アダプターを使用して、SimpleInjectorを次のように構成できます。
_container.RegisterInstance<ILoggerFactory>(factory);
container.RegisterConditional(
typeof(MyApplication.Abstractions.ILogger),
c => typeof(MicrosoftLoggingAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
_ => true);
_
スティーブンの解決策に基づいて、私は他の誰かを助けるために私の答えを投稿します:
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);
}
}
ご覧のとおり、私のソリューションはMicrosoft.Extensions.Logging
にログインするためのプロバイダーとしてSerilogを使用しています。
それが役に立てば幸い!