1

我有引用多个库(核心、标准)的 ac# 项目。每个库都以下列方式使用 log4net:

public class LibOne
{
    private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    public LibOne()
    {
        Log.Debug("ctor called");
    }
}

主工程配置Logger:

XmlConfigurator.Configure(LogManager.GetRepository(Assembly.GetEntryAssembly()),
                new FileInfo($"{AppDomain.CurrentDomain.BaseDirectory}\\log4net.config"));

层次结构如下所示:

         MainProject
             |
   +---------+---------+
LibOne    LibTwo    LibThree
   |                   |
   |                   +---------+
   +---------+      LibSix    LibSeven
LibFour   LibFive

好的,通过上述设置,我可以看到每个库的日志条目。


现在这些库应该现代化并变得更加通用,以便消费者可以决定他最喜欢的记录器(例如 NLog、Console 等)。因此我想使用Microsoft.Logging.Extensions. 我已经阅读了很多文档、指南、提示等,并发现这ILoggerFactory可能是最好的开始方式,但是

  1. 没有人解释,如何使用ILogger多层以及如何在消费项目中配置记录器,
  2. 几乎我发现的每个示例都在 DI 的构造函数中添加了ILogger/ILogger<T>参数,但我无法更改每个库的构造函数的签名。有没有办法以不同的方式做到这一点?
  3. 我读过一些关于autofac但没有完全理解的东西。也许我可以用它来定义我想在日志文件中看到哪些类型/库?

UPD 1 是否有可能更改库代码并以与 log4net 相同的方式处理它,但使用未指定的 logprovider,例如

public class LibOne
{
    private static readonly ILogger<LibOne> Log = new LoggerFactory().CreateLogger<LibOne>(); //does this make sense?

    public LibOne()
    {
        Log.LogDebug("ctor called");
    }
}

那么如何在我的主项目中配置记录器(例如 log4net 或调试控制台)?我以后可以添加提供者吗?

很抱歉这些问题,但微软关于超出 asp.net 范围(并且没有 DependencyService)的日志记录扩展的文档真的很差。

4

1 回答 1

1

没有人解释,如何使用ILogger多层以及如何在消费项目中配置记录器

我认为您必须详细说明我的“多层”是什么意思。一般约定是每个需要做一些记录的类都需要它自己的记录器实例:

class MyController
{
    private readonly ILogger _logger;
    public MyController(ILogger<MyController> logger)
    {
        _logger = logger;
    }
}

// ...

class MyRepository
{
    private readonly ILogger _logger;
    public MyController(ILogger<MyRepository> logger)
    {
        _logger = logger;
    }
}

或者,如果您希望能够按一些更常见的类别对日志进行“分组”,而不是按类对日志进行分类,您可以使用ILoggerFactory

class MyController
{
    private readonly ILogger _logger;
    public MyController(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger("Controller");
    }
}

// ...

class MyRepository
{
    private readonly ILogger _logger;
    public MyController(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger("Repository");
    }
}

几乎我发现的每个示例都在 DI 的构造函数中添加了ILogger/ILogger<T>参数,但我无法更改每个库的构造函数的签名。有没有办法以不同的方式做到这一点?

我认为您和您的团队应该真正考虑一下为什么您有不修改构造函数的要求。如果您没有在构造函数或方法中注入记录器的依赖项,那么您必须通过 DI 容器显式解析记录器服务,这意味着您正在向消费者的依赖注入 (DI) 框架添加依赖项您的图书馆将需要使用。当然,您可以制作一个自定义解决方案来包装 DI 框架,以避免对特定 DI 框架的硬依赖,但我认为这样会给自己带来更多麻烦。

换句话说:除非您想自己使事情复杂化,否则您将无法避免通过此重构来破坏更改。因此,我建议您重新考虑不更改构造函数签名的要求。如果你真的想要,你可以用一个可选ILogger参数来扩展构造函数,这样可以减少重大变化,但现在你的类需要准备好不传入记录器。

给你一个不通过构造函数注入依赖的例子:

class MyStartupClass
{
    public static SomeDiLibrary.ContainerType Container;

    public SetupApplication()
    {
        Container = new SomeDiLibrary.ContainerType();
        Container.ConfigureServices(...);
    }
}

class MyController
{
    private readonly ILogger _logger;
    public MyController()
    {
        // Explicitly resolve an ILogger using the DI framework
        _logger = MyStartupClass.Container.Resolve<ILogger>();
    }
}

如您所见,MyController现在依赖于使用SomeDiLibrary作为 DI 框架。因此,使用您的项目的项目也需要使用SomeDiLibrary才能“注入”他们自己的记录器类型。如果一个消费者项目想要使用不同的 DI 框架,它不会和你的一起玩。此外-在我非常简化的示例中-您将面临如何使 DI 容器可访问的问题MyController。我猜你正在构建一些类库,这意味着你没有像这样的设置类MyStartupClass,那么从哪里MyController获取容器呢?

也许那里有图书馆可以帮助您克服这个问题,但我不知道。

我读过一些关于autofac但没有完全理解的东西。也许我可以用它来定义我想在日志文件中看到哪些类型/库?

Autofac 只是更常见的依赖注入框架之一。同样,您有 Castle Windsor、Spring.NET、Ninject 等等我听说过的。这就是SomeDiLibrary上面的构成。

总结一下 DI 是什么:

使用 DI,您通常旨在使用接口在类中定义依赖关系。该类通常将所有依赖项(即其他类/服务的实例)作为构造函数中的输入。

以上允许您动态选择您希望类使用的接口的实现。想象一下,您有一个UserRepository和一个控制器,它使用这个存储库直接从数据库中查找用户。如果您的控制器经常查找相同的用户,您可能希望缓存一些结果,而不是每次都查询数据库。所以你的控制器想UserRepositoryCache改用。这需要修改控制器类。但是,您可以依赖一个通用接口IUserRepository,然后由 DI 框架来配置在实例化时向控制器提供哪个实现(UserRepository或)。UserRepositoryCache

您可能会找到对 DI 和 DI 框架的更好解释,但希望它能给您一个想法。

于 2020-11-26T21:54:54.197 回答