简单的注入器:注册 ILogger&lt;T&gt;通过使用 ILoggerFactory.CreateLogger<T>() [英] Simple Injector: Register ILogger&lt;T&gt; by using ILoggerFactory.CreateLogger&lt;T&gt;()

查看:72
本文介绍了简单的注入器:注册 ILogger&lt;T&gt;通过使用 ILoggerFactory.CreateLogger<T>()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理一个使用 Simple Injector 作为依赖注入器的项目.另一方面,该项目使用 Microsoft.Extensions.Logging 来记录某些类中发生的事件.

我的技术问题很容易解释.我想在我的 DI 中注册独立于被调用的类 T 的 ILogger,但是我需要从我的 ILoggerFactory.CreateLogger()方法,因为这使用 Microsoft.Extensions.Configuration 获取记录器配置.

我需要使用这样的东西来实例化我的记录器:

private Microsoft.Extensions.Logging.ILogger CreateLogger(){var factory = this.ResolveService();var logger = factory.CreateLogger();返回记录器;}

我可以通过以下方式实现注入:

Container.Register(typeof(ILogger<>), typeof(Logger<>));

这使我们能够解决以下问题:

public class SomeApiController : ApiController{公共 SomeApiController(ILogger logger){//logger实例化好了,但是没有得到配置logger.LogInformation(测试日志");}}

但正如我所说,这样做没有通过从 Microsoft.Extensions.Logging.ILoggerFactory 类获得的配置,所以这没有用.

有没有办法使用我的CreateLogger来注册ILogger?

解决方案

使用以下注册:

container.RegisterInstance(loggerFactory);container.RegisterSingleton(typeof(ILogger<>), typeof(Logger<>));

或者,如果您要将 Simple Injector 集成到通用主机或 ASP.NET Core 应用程序中,请使用 .AddLogging() 扩展方法甚至可以将非通用的 ILogger 注入到您的应用程序组件中,如这个 ASP.NET Core Startup 类所示:

公共类启动{...public void ConfigureServices(IServiceCollection 服务){services.AddLogging();//向框架添加日志记录//AddSimpleInjector 启用交叉布线",这意味着你可以让//简单的 Injector-resolved 组件依赖于泛型//ILogger抽象.services.AddSimpleInjector(container, options =>{options.AddAspNetCore();//AddLogger 允许 Simple Injector-resolved 组件依赖//非通用 Microsoft.Extensions.Logging.ILogger 接口.//Simple Injector 会自动注入正确的 ILogger;//为你.options.AddLogging();});}...}

有关完整示例,请参阅 ASP.NET Core 和 ASP.NET Core MVC 集成指南.>

让应用程序组件依赖于 ILogger 而不是 ILogger,使您的代码更简单、更易于测试并且不易出错.如果您使用的是没有 服务集合集成的 Simple Injector(如前面的示例所示,您可以使用以下注册来让 Simple Injector 确保在注入 ILogger 时仍然注入正确的 Logger:

container.RegisterConditional(类型(ILogger),c =>typeof(Logger<>).MakeGenericType(c.Consumer.ImplementationType),生活方式.单身,_ =>真的);

这确保每个应用程序组件都有自己的 Logger 实例,其中 T 是记录器注入的组件的类型.以下面这个依赖于ILogger的类为例:

public class ComponentA : IService{公共 ComponentA(ILogger 记录器) { ... }}

上述注册将确保 ComponentA 被注入一个 Logger,即使它仅仅依赖于 ILogger 而不是ILogger.

如果以上内容满足您的需求,您可以在此处停止阅读……如果您对更可靠的解决方案感兴趣,请继续阅读.

可靠的解决方案

不是让应用程序组件依赖于框架定义的 ILogger 抽象,您还可以选择定义特定于应用程序的记录器抽象,如 依赖倒置原则 (DIP).

DIP 声明抽象应该由应用程序本身定义——这意味着你定义自己的记录器抽象(另请参阅 this 以了解您为什么要这样做)和最重要的是,您构建了一个适配器,非常类似于 这里.您可以简单地从描述的 MicrosoftLoggingAdapter 派生您的通用适配器,如下所示:

公共密封类 MicrosoftLoggingAdapter;: MicrosoftLoggingAdapter{公共 MicrosoftLoggingAdapter(ILoggerFactory 工厂):基地(工厂.CreateLogger()){}}

使用此通用适配器,您可以按如下方式配置 Simple Injector:

container.RegisterInstance(工厂);container.RegisterConditional(typeof(MyApplication.Abstractions.ILogger),c =>typeof(MicrosoftLoggingAdapter<>).MakeGenericType(c.Consumer.ImplementationType),生活方式.单身,_ =>真的);

I'm working with a project which utilizes Simple Injector as dependency injector. On the other hand, this project uses Microsoft.Extensions.Logging in order to log the events that occurs in certain classes.

My technical issue is pretty simple to explain. I want to register in my DI the ILogger independently of the class T which is being invoked, but I DO NEED to do it from my ILoggerFactory.CreateLogger<T>() method because this gets the logger configuration using Microsoft.Extensions.Configuration.

I need to use something like this in order to instance my logger:

private Microsoft.Extensions.Logging.ILogger CreateLogger<T>()
{
     var factory = this.ResolveService<ILoggerFactory>();
     var logger = factory.CreateLogger<T>();
     return logger;
}

I could achieve the injection by doing:

Container.Register(typeof(ILogger<>), typeof(Logger<>));

And this allows us to resolve something like:

public class SomeApiController : ApiController
{
     public SomeApiController(ILogger<SomeApiController> logger)
     {
         //logger is well instantiated, but doesn't got the configuration
         logger.LogInformation("test log.");
     }
}

But as I said, this does it without passing through the configuration obtained from the Microsoft.Extensions.Logging.ILoggerFactory class, so this isn't useful.

Is there a way to register ILogger<T> by using my CreateLogger<T>?

解决方案

Use the following registrations:

container.RegisterInstance<ILoggerFactory>(loggerFactory);
container.RegisterSingleton(typeof(ILogger<>), typeof(Logger<>));

Or, in case you are integrating Simple Injector into a generic host or ASP.NET Core application, make use of the .AddLogging() extension method to even inject a non-generic ILogger into your application components, as demonstrates in this ASP.NET Core Startup class:

public class Startup
{
    ...

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddLogging(); // Adds logging to the framework

        // AddSimpleInjector enables "cross wiring," which means you can let
        // Simple Injector-resolved components to depend on the generic
        // ILogger<T> abstraction.
        services.AddSimpleInjector(container, options =>
        {
            options.AddAspNetCore();
            
            // AddLogger allows Simple Injector-resolved components to depend on 
            // the non-generic Microsoft.Extensions.Logging.ILogger interface.
            // Simple Injector will automatically inject the correct ILogger<T>
            // for you.
            options.AddLogging();
        });
    }

    ...
}

For a full example, see the ASP.NET Core and ASP.NET Core MVC Integration Guide.

Letting application components depend on ILogger instead of ILogger<T>, makes your code simpler, easier to test, and less error prone. If you're using Simple Injector without Service Collection integration (as the previous example showed, you can use the following registration to let Simple Injector ensure the correct Logger<T> is still injected whenever an ILogger is injected:

container.RegisterConditional(
    typeof(ILogger),
    c => typeof(Logger<>).MakeGenericType(c.Consumer.ImplementationType),
    Lifestyle.Singleton,
    _ => true);

This ensures that every application component gets its own Logger<T> instance, where T is the type of the component the logger is injected into. Take the following class for example that depends on ILogger:

public class ComponentA : IService
{
    public ComponentA(ILogger logger) { ... }
}

The above registration will ensure that ComponentA is injected with a Logger<ComponentA>, even though it simply depends on ILogger and not on ILogger<T>.

You can stop reading here if the above suits your needs... or continue reading if you're interested in a more SOLID solution.

A SOLID solution

Instead of letting application components depend on the framework-defined ILogger abstraction, you could also choose to define an application-specific logger abstraction, as prescribed by the Dependency Inversion Principle (DIP).

The DIP states that abstractions should be defined by the application itself—this means you define your own logger abstraction (also see this for an explanation of why you want to do this) and on top of that you build an adapter, much like described here. You can simply derive your generic adapter from the described MicrosoftLoggingAdapter as follows:

public sealed class MicrosoftLoggingAdapter<T> : MicrosoftLoggingAdapter 
{
    public MicrosoftLoggingAdapter(ILoggerFactory factory) 
        : base(factory.CreateLogger<T>()) { }
}

Using this generic adapter, you can configure Simple Injector as follows:

container.RegisterInstance<ILoggerFactory>(factory);

container.RegisterConditional(
    typeof(MyApplication.Abstractions.ILogger),
    c => typeof(MicrosoftLoggingAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
    Lifestyle.Singleton,
    _ => true);

这篇关于简单的注入器:注册 ILogger&lt;T&gt;通过使用 ILoggerFactory.CreateLogger<T>()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆