これは、AspNet Core のコンストラクターに ILogger または ILoggerFactory を渡しますか?と多少関連している可能性がありますが、これは具体的にはライブラリ設計に関するものであり、それらのライブラリを使用する実際のアプリケーションがログ記録を実装する方法に関するものではありません。
私は、Nuget 経由でインストールされる .net Standard 2.0 ライブラリを作成しており、そのライブラリを使用するユーザーがデバッグ情報を取得できるようにするために、標準化された Logger を挿入できるようにMicrosoft.Extensions.Logging.Abstractionsに依存しています。
ただし、複数のインターフェイスが見られ、Web 上のサンプル コードではILoggerFactory
、クラスの ctor でロガーが使用および作成されることがあります。FactoryILoggerProvider
の読み取り専用バージョンのように見えるものもありますが、実装では両方のインターフェイスが実装される場合と実装されない場合があるため、どちらかを選択する必要があります (Factory は Provider よりも一般的なようです)。
私が見たコードの中には、非ジェネリックILogger
インターフェイスを使用していて、同じロガーのインスタンスを 1 つ共有しているものもあれば、ILogger<T>
コンストラクターに を取り込んで、DI コンテナーがオープン ジェネリック型をサポートするか、ライブラリが使用するすべてのILogger<T>
バリエーションの明示的な登録をサポートすることを期待しているものもあります。
現時点では、それが正しいアプローチだと思いますILogger<T>
。おそらく、その引数を取らずに Null Logger を渡すだけの ctor でしょう。そうすれば、ログ記録が必要ない場合は何も使用されません。ただし、一部の DI コンテナーは最大の ctor を選択するため、いずれにしても失敗します。
必要に応じて適切なログ記録サポートを可能にしながら、ユーザーの負担を最小限に抑えるためにここで何をすべきか興味があります。
ベストアンサー1
意味
インターフェースは 、 の 3 つありますILogger
。ILoggerProvider
ソースコードILoggerFactory
を見て、それぞれの役割を確認しましょう。
ILogger : 指定されたログ レベルのログ メッセージを書き込む役割を担います。
ILoggerProvider : インスタンスの作成を担当しますILogger
(ILoggerProvider
ロガーの作成に直接使用することは想定されていません)
ILoggerFactory : 1 つ以上のILoggerProvider
をファクトリに登録できます。ファクトリは、それらすべてを使用して のインスタンスを作成しますILogger
。ILoggerFactory
は のコレクションを保持しますILoggerProviders
。
以下の例では、2 つのプロバイダー (コンソールとファイル) をファクトリーに登録しています。ロガーを作成すると、ファクトリーはこれらのプロバイダーの両方を使用して次のインスタンスを作成しますLogger
。
ILoggerFactory factory = new LoggerFactory().AddConsole(); // add console provider
factory.AddProvider(new LoggerFileProvider("c:\\log.txt")); // add file provider
Logger logger = factory.CreateLogger(); // creates a console logger and a file logger
したがって、ロガー自体は のコレクションを維持しILogger
、それらすべてにログ メッセージを書き込みます。Loggerのソース コードを見ると、 には(つまり)Logger
の配列があり、同時にインターフェイスを実装していることが確認できます。ILoggers
LoggerInformation[]
ILogger
依存性注入
MS ドキュメントには、ロガーを挿入するための 2 つの方法が提供されています。
1. ファクトリーの注入:
public TodoController(ITodoRepository todoRepository, ILoggerFactory logger) { _todoRepository = todoRepository; _logger = logger.CreateLogger("TodoApi.Controllers.TodoController"); }
Category = TodoApi.Controllers.TodoController の Logger を作成します。
2. ジェネリックの注入
ILogger<T>
:public TodoController(ITodoRepository todoRepository, ILogger<TodoController> logger) { _todoRepository = todoRepository; _logger = logger; }
カテゴリ = TodoController の完全修飾型名を持つロガーを作成します。
私の意見では、ドキュメントがわかりにくいのは、非ジェネリックの を注入することについて何も言及されていないことです。ILogger
上記の同じ例では、非ジェネリックを注入していますITodoRepository
が、 に対して同じことを行わない理由が説明されていませんILogger
。
マーク・シーマンによれば:
インジェクション コンストラクターは依存関係を受け取る以上のことは行わないでください。
ファクトリをコントローラーに注入するのは良い方法ではありません。なぜなら、ロガーを初期化するのはコントローラーの責任ではないからです (SRP 違反)。同時に、ジェネリックを注入すると不要なノイズが追加されます。詳細については、Simple Injector のブログ「 ASP.NET Core DI 抽象化の何が問題なのか?」ILogger<T>
を参照してください。
注入すべきものは (少なくとも上記の記事によれば) 非ジェネリックですILogger
が、それは Microsoft の組み込み DI コンテナーでは実行できないため、サードパーティの DI ライブラリを使用する必要があります。これらの 2 つのドキュメントでは、.NET Core でサードパーティのライブラリを使用する方法について説明しています。
これはNikola Malovic による別の記事で、彼が IoC の 5 つの法則について説明しています。
ニコラの IoC の第 4 法則
解決されるクラスのすべてのコンストラクターには、独自の依存関係のセットを受け入れる以外の実装があってはなりません。