首页 文章

在从ASP.NET核心Web应用程序调用的动态发现的.NET Core类库中注入 Logger 的合适模式是什么?

提问于
浏览
9

概述

我正在尝试将基于.NET Framework的许多项目移植到.NET Core . 这涉及移植许多类库以及使用这些库的顶级控制台/ Web应用程序 .

我的部分要求是我的顶级应用程序应该支持基于插件的系统,我可以通过引用这些类库的不同子集来轻松地交换功能 . 我用过MEF来做这个 . 例如,我的一个ASP.NET核心Web应用程序涉及通过 ICommunicationService 与设备通信,我有不同的Nuget包导出此服务的不同实现:

[Export(typeof(ICommunicationService))]
[Shared]
public sealed class UsbCommunicationService : ICommunicationService
{
}

重新设计类库

目前,这些类库引用 Common.Logging 并将 Logger 实例化为只读静态字段:

[Export(typeof(ICommunicationService))]
[Shared]
public sealed class UsbCommunicationService : ICommunicationService
{
    ...
    private static readonly ILog Log = LogManager.GetLogger<UsbCommunicationService>();
    ....
}

我在我的顶级应用程序中使用了 Log4Net ,并通过引用 Common.Logging.Log4Net 适配器来促进我的类库中的日志记录 .

但是,我知道ASP.NET Core依赖于Microsoft的新日志抽象框架 Microsoft.Extensions.Logging ,并且ASP.NET Core应用程序应该设计为通过构造函数依赖注入 Logger 来支持日志记录,如下所示:

public class HomeController : Controller
{
    private ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }

    public IActionResult Index()
    {
        _logger.LogInformation("Index action requested at {requestTime}", DateTime.Now);
        return View();
    }
}

我不完全确定在我的新.NET Core库和应用程序中使用哪种日志框架组合(see this related post),但我倾向于在类库中使用 Common.Logging 切换到 Microsoft.Extensions.Logging . 在那种情况下,我想知道我应该如何处理 Logger 的实例化 . 这样的事情会合适吗?

using Microsoft.Extensions.Logging;
...
[ImportingConstructor]
public UsbCommunicationService(
    [Import] IUsbMessageEncoder encoder,
    [Import] IUsbMessageDecoder decoder,
    [Import] ILogger<UsbCommunicationService> logger /* Add this new import */)
{
    ...
}

换句话说,我是否应该将需要记录的所有类库切换为在构造期间注入这些 Logger ?

消费类库

基于this answer to a similar question,我觉得上面详述的方法是沿着正确的方向 . 但是,我不确定如何在ASP.NET Core应用程序中使用和正确实例化类库中定义的服务 .

ASP.NET Core使用自己的依赖注入服务,该服务与MEF完全分离 . 我不能简单地在我的Web应用程序中编写类似_2967633的内容,原因有两个:

  • 这个想法是支持一个基于插件的系统,其中动态发现插件,因此"core"应用程序本身不能对其进行硬性引用 .

  • ASP.NET核心's service injector and wouldn'不知道 UsbCommunicationService - IUsbMessageEncoderIUsbMessageDecoder 的其他依赖项 .

同样,我不能使用MEF来获取 UsbCommunicationService 的实例,因为它无法解析对 ILogger<UsbCommunicationService> 的引用 .

摘要

简而言之,我正在尝试寻找以下解决方案:

  • 促进.NET Core库中的日志记录,为日志记录提供程序提供最大的灵活性 .

  • 允许使用依赖项注入将 Logger 提供给这些类库 .

  • 允许顶级ASP.NET Core或.NET Core控制台应用程序在运行时动态发现和加载这些.NET Core库,并为它们提供 Logger 或 Logger 工厂,以便顶级应用程序和所有加载的插件使用常见的日志记录提供程序(例如Serilog,NLog,Log4Net等) .

  • 例如,如果我想使用Log4Net的 ColoredConsoleAppender ,我应该会看到所有ASP.NET日志和类库日志都出现在同一个控制台中 .

1 回答

  • 4

    Microsoft.Extensions.Logging不是严格的日志框架;它's a facade. There'的内置实现,如 DebugTraceConsole 等,但's just for ease. In actual use, you'可能插入像Serilog这样的东西 . Serilog实际上是处理日志记录的,而Microsoft.Extensions.Logging只是提供"logging"的抽象方式,而不必实际使您的应用程序代码明确依赖于Serilog的API .

    Common.Logging也是一个外观,在这种情况下,你选择插入log4net作为正在使用的实际 Logger . 但是,这可以改变 . 鉴于此,您可以采取一些可能的路径 .

    • 在ASP.NET Core应用程序中使用Common.Logging切换Microsoft.Extensions.Logging . 是的,你可以做到这一点 . 就个人而言,我认为Microsoft.Extensions.Logging更好,但你可以使用你喜欢的任何东西 .

    • 在类库中使用Microsoft.Extensions.Logging切换Common.Logging . 如果你要改写它们,这可能是最有意义的,但就代码中需要更改的内容而言,它也涉及最大的摩擦 .

    • 为使用Microsoft.Extensions.Logging的Common.Logging编写适配器 . 这无疑是有点元,但从技术上讲,简单地使用一个外观来处理另一个外观以最终使用特定的日志框架是没有错的 . 这就是适配器模式的全部要点 . 这也为您提供了两全其美的优势:您不需要在库或ASP.NET Core应用程序中进行太多更改 . 但是,由于游戏中存在多个外观,它确实会增加代码的熵 . 虽然不可能说,但我实际上并没有看到Common.Logging继续保持未来 . 既然微软有几乎内置的外观,我希望看到它几乎占据主导地位 . 现在可能是最好的跳船,而你已经进行了一些返工 .

相关问题