两个派生类如何共享Microsoft.Extensions.Logging.ILogger <t>日志框架?

时间:2018-03-30 18:19:39

标签: c# asp.net-core asp.net-core-mvc

在ASP.NET Core中,默认解析程序将解析控制器中的Microsoft.Extensions.Logging.ILogger<MyClass>

假设我创建了一个从控制器调用的新.NET标准库。

如何将Microsoft.Extensions.Logging实例传递给它?

  • 如果需要new(),如何创建班级的ILogger<MyClass2>个实例?
  • C#可以为ILogger<T>手动自动化,我可以将其传递到我的库中吗?

2 个答案:

答案 0 :(得分:1)

有时候,依赖注入不可用-或者当您处在不应该使用DI的环境中(例如单元测试,您将明确定义每个注入的服务),同理某些形式的集成测试。

在这种情况下-如果您不关心日志记录(例如,在进行原型设计或实验时),请使用NullLogger内置的Microsoft.Extensions.Logging.Abstractions(即通用 NuGet程序包,所有使用MEL的项目都必须引用该程序包,因此可以保证该程序包可用)。

例如,如果您的服务实现需要非空的ILogger<T>

public interface IEncabulatorService
{
    void Foo();
}

public class TurboEncabulatorService : IEncabulatorService
{
    private readonly ILogger log;

    public TurboEncabulatorService( ILogger<TurboEncabulatorService> log )
    {
        this.log = log ?? throw new ArgumentNullException(nameof(log));
    }

    public void Foo()
    {
        this.log.LogInformation( "Foo was invoked." );
    }
}

然后,您可以使用NullLogger虚拟记录器(例如,在单元测试项目中)实例化它,如下所示:

using Microsoft.Extensions.Logging; // This namespace must be imported because it uses extension-methods.
using Microsoft.Extensions.Logging.Abstractions;

[TestClass]
public class MyTests
{
    [TestMethod]
    public void TestEncabulator()
    {
        ILogger<TurboEncabulatorService> log = NullLoggerFactory.Instance.CreateLogger<TurboEncabulatorService>()

        IEncabulatorService service = new TurboEncabulatorService( log );
    }
}

如果您确实关心记录的内容,那么很遗憾,您确实需要实现自己的ILoggerFactory(并记录到一些内部缓冲区),但是您无需提供您的记录。自己的CreateLogger<T>()方法来创建强类型的ILogger<T>实例,因为MEL库中作为扩展方法免费提供了该实例。

关于子类

您在帖子中提到了“派生”类-因为如果您有这个...

public class BaseService
{
    public BaseService( ILogger<BaseService> log )
    {
        // ...
    }
}

public class DerivedService : BaseService
{
    // ...?
}

...您可能想知道DerivedService是否应该接受ILogger<BaseService>ILogger<DerivedService>,因为肯定需要ILogger<BaseService>才能传递给BaseService ,但是DerivedService将失去其强类型类别名称。

...但事实并非如此!如果查看ILogger<T>的定义,您会发现它是convariant generic interface because it has <out T> rather than just <T>。这意味着任何接受ILogger<Base>的变量,方法或构造函数也将接受ILogger<Derived>

所以你有这个,这是完全合法的:

public class BaseService
{
    public BaseService( ILogger<BaseService> log )
    {
        // ...
    }
}

public class DerivedService : BaseService
{
    public DerivedService( ILogger<DerivedService> log )
        : base( log ) // `ILogger<BaseService>` can accept an `ILogger<DerivedService>`!
    {
    }
}

按照我之前的示例,您可以使用DerivedService实例化BaseServiceNullLogger的实例:

BaseService bs = new BaseService( NullLoggerFactory.Instance.CreateLogger<BaseService>() );

DerivedService ds = new DerivedService ( NullLoggerFactory.Instance.CreateLogger<DerivedService>() );

工厂助手:

如果您发现自己需要频繁进行NullLogger(或自己的ILogger实现),则可以使用以下工厂帮助方法:

public static TService CreateServiceWithLogger<TService>( Func<ILogger<TService>,TService> ctor )
{
    ILogger<TService> log = NullLoggerFactory.Instance.CreateLogger<TService>();
    return ctor( log );
}

C#的类型推断规则将确保您不需要提供显式的TService泛型参数类型参数,例如:

TurboEncabulatorService service = CreateServiceWithNullLogger( log => new TurboEncabulatorService( log ) );

答案 1 :(得分:0)

您应该使用依赖注入。

您的Controller通过在其构造函数中引用接口来利用DI资源。对于ILogger<Class>,这看起来像:

public class MyAwesomeController : Controller
{
    private readonly ILogger _logger;

    public MyAwesomeController(ILogger<MyAwesomeController> logger)
    {
        // logger contains a refference to the DIed ILogger 
        // We assign it to _logger so we can reference it from other
        // methods in the class
        _logger = logger;
    }

    public IActionResult GetIndex()
    {
        // Log something
        //_logger.LogInformation();
        return View();
    }
}

您可以在文档中找到更多详细信息:Logging in ASP.NET Core