【问题标题】:Separation of Logging between derived and base classes with Dependency Injection C#使用依赖注入 C# 在派生类和基类之间分离日志记录
【发布时间】:2021-06-24 15:35:54
【问题描述】:

类似于 SO (Dependency injection in base and derived classes),我希望将基类和派生类的日志记录“类别”分开。我在 SO 中尝试了两种答案的变体,但没有得到想要的结果。

正在使用的记录器是:Microsoft.Extensions.Logging

基类: 到目前为止,最大的努力是尝试正确投射它,但这没有奏效。

public abstract class LifetimeEventsHostedService : IHostedService
{
  private readonly ILogger<LifetimeEventsHostedService> _logger;
  protected LifetimeEventsHostedService(ILogger logger)
  {
    _logger = (ILogger<LifetimeEventsHostedService>)logger;
  }
  public virtual Task StartAsync(CancellationToken cancellationToken)
  {
    _logger.LogInformation("LifetimeEventsHostedService.StartAsync has been called");
  }  
}

派生类:

public class DerivedHostedService: LifetimeEventsHostedService
{
  private readonly ILogger<DerivedHostedService> _logger;

  public DerivedHostedService(ILogger<DerivedHostedService> logger) : base(logger) 
  {
    _logger = logger;
  }

  public override async Task StartAsync(CancellationToken cancellationToken)
  {
    await base.StartAsync(cancellationToken);
    _logger.LogInformation("StartAsync completed");
  }
}

现在控制台日志显示如下:

info: PlayerService.Services.HostedServices.DerivedHostedService[0] // Should show as base class category
      LifetimeEventsHostedService.StartAsync has been called        // Hacky workaround to include base category in the message
info: PlayerService.Services.HostedServices.DerivedHostedService[0] // Obviously (correctly) showing correct in derived class
      StartAsync completed
info: PlayerService.Services.HostedServices.DerivedHostedService[0] // Should show as base class category
      LifetimeEventsHostedService.OnStarted has been called         // Hacky workaround to include base category in the message
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.

我在上面完成它的方式有效,但我想找到一种方法将type(类别)设置为基类,将基类与派生类分开并省略hacky(额外细节/基类名称),而是尽可能保持两者之间的日志分离。

【问题讨论】:

  • 是的,我意识到不将它们分开的含义和价值。
  • 根据您想要的功能,它需要单独的记录器实例。在这里投射是行不通的
  • @Nkosi 嗯,这是有道理的,从逻辑上讲,我现在这样做的“hacky”方式仍然是最简单的(并且可能是更好的解决方案,考虑到分离的含义,在日志中保留适当的上下文第一名)。创建基类的单独实例并注入它而不是从它派生,虽然另一种选择似乎适得其反。
  • 为什么不在派生类中请求两个记录器? public DerivedHostedService(ILogger&lt;DerivedHostedService&gt; logger, ILogger&lt;LifetimeEventsHostedService&gt; baseLogger) : base(baseLogger)
  • @qujck 你知道,我确实尝试过,但它在 IDE 中给了我一个 Roslyn 警告,所以我在实际上尝试之前放弃了它。虽然当我刚刚测试它时没有编译器警告,实际上确实提供了我正在寻找的结果。请随时提供作为答案,我会标记它。

标签: c# logging dependency-injection


【解决方案1】:

您可以请求派生类中的两个记录器:

public DerivedHostedService(
    ILogger<DerivedHostedService> logger, 
    ILogger<LifetimeEventsHostedService> baseLogger) : base(baseLogger)
{}

【讨论】:

  • 谢谢,正如上面在 cmets 中所述,我确实开始了这条路(并过早地放弃了它),但 IDE 会将其显示为警告(抱歉不是 Roslyn,这可能是 Rider 特定的警告或可能的其他 IDE),但可以禁用。 警告(对其他人):这不是最佳做法,可能应该避免,除非您有非常具体的理由将两者分开。
【解决方案2】:

如果您最终在基类中需要多个服务,但又不希望每个派生类都必须全部调用它们,那么这是另一种选择。我个人会避免它,但它可能会绕过你收到的警告,尽管我个人认为你有“非常具体的理由将两者分开”。

   public DerivedHostedService(
        ILogger<DerivedHostedService> logger, 
        IServiceProvider services) : base(services)
    {}

    public BaseHostedService(
        IServiceProvider services)
    {

      var logger = services.GetRequiredService<ILogger<BaseHostedService>>();

      // etc

    }

【讨论】:

  • 不错的替代方案,当然会破坏 DI,并且可能会引起一些安全问题,但我喜欢它作为一个 hacky 替代方案。
  • 我不会说它完全破坏了 DI,因为您将始终能够注入服务提供者。
猜你喜欢
  • 2012-03-08
  • 2013-07-10
  • 1970-01-01
  • 2017-07-17
  • 1970-01-01
  • 2020-01-20
  • 1970-01-01
  • 1970-01-01
  • 2010-11-13
相关资源
最近更新 更多