如何使用相同接口的2个不同对象(log4net记录器)连接StructureMap

时间:2014-06-25 15:58:30

标签: c# log4net structuremap structuremap3

我有一个名为MyClass的类,它使用两个名为Logger1Logger2的不同记录器。我使用log4net进行日志记录,并希望将StructureMap用于DI。

如果没有StructureMap,我的课将如下所示:

public class MyClass
{
    private static readonly ILog Logger1 = LogManager.GetLogger("Logger1"); // Loggers are configured in a config file
    private static readonly ILog Logger2 = LogManager.GetLogger("Logger2");

    public void DoSomething()
    {
        ...
        Logger1.Info("did something");
        ...
        Logger2.Info("need to log this elsewhere");
    }
 }

使用StructureMap(使用v3.0.3)介绍DI,我将使loggers实例成员,并将它们注入构造函数,如下所示:     公共类MyClass     {         私人只读ILog Logger1;         私人只读ILog Logger2;

    myClass(ILog logger1, ILog logger2)
    {
        this.Logger1 = logger1;
        this.Logger2 = logger2;
    }

    public void DoSomething()
    {
        ...
        Logger1.Info("did something");
        ...
        Logger2.Info("need to log this elsewhere");
    }
 }

问题是,我无法让StructureMap为我正确连接。我尝试像这样连接记录器:

For<ILog>.Use(()=> LogManager.GetLogger("Logger1")).Named("Logger1");
For<ILog>.Use(()=> LogManager.GetLogger("Logger2")).Named("Logger2");

执行此操作获取空(未配置)记录器)。用Use()替换Add()会导致我的异常,因为没有为ILog注册默认实例。

有人知道我该怎么做吗?

3 个答案:

答案 0 :(得分:4)

如果记录器执行不同的角色,那么我将创建两个继承自ILog的接口来反映这一点。这样,配置StructureMap来处理它们就没有问题了。

答案 1 :(得分:0)

我最终执行了以下操作:根据Rob的建议创建了两个界面:ILogger1ILogger2。由于两者都具有相同的API,因为我需要相同的功能,它们都从相同的接口继承 - 尽管 log4net.ILog按照史蒂文的建议:

interface IMyLog
{
    void Info(object message);
    void Info(string format, params object[] args);
}

interface ILogger1 : IMyLog { }
interface ILogger2 : IMyLog { }

此外,由于此API的实现与我的需求相同,因此我有一个具体的类MyLogger,同时实现ILogger1ILogger2。如果我需要实现不同,那么我将很容易有明确的接口实现或单独的类。只有My Logger依赖于log4net,因为它将其用于实现:

enum LoggerType { Logger1, Logger2 }

internal class MyLogger : ILogger1, ILogger2
{
    private readonly ILog _log;

    public MyLogger(LoggerType loggerName)
    {
        switch (loggerName)
        {
            case LoggerType.Logger1:
                _log = LogManager.GetLogger("first-log");
                break;
            case LoggerType.Logger2:
                _log = LogManager.GetLogger("second-log");
                break;
            default:
                throw new ArgumentException("Invalid logger name", "loggerName");
        }
    }

    public void Info(object message)
    {
        _log.Info(message);
    }

    public void Info(string format, params object[] args)
    {
        _log.InfoFormat(format, args);
    }
} 

为了使用 StructureMap 注册它,我在注册表中使用了以下代码:

For<ILogger1>().Use<MyLogger>().Ctor<LoggerType>("loggerName").Is(LoggerType.Logger1).Singleton();   // I want only one logger per type
For<ILogger2>().Use<MyLogger>().Ctor<LoggerType>("loggerName").Is(LoggerType.Logger2).Singleton();

这一切都很有效。所以,感谢Steven和Rob的建议。我真的学到了点东西。我希望我能不止一次地回答答案和答复。

总而言之,我:

  • 为每种记录器创建一个单独的界面(甚至说它现在听起来很直观)。
  • 为记录器接口创建了一个基本界面,因为满足我的需求他们拥有相同的API(YMMV)
  • 创建了一个实现两个接口的具体记录器适配器,因为它适合我的需求(YMMV再次)
  • 分享接口的实现&#39; API,出于上述原因
  • 注册每个接口以创建具有在构造函数中传递的不同类型的具体记录器
  • 使用Factory Method使用log4net配置具体记录器以确定要使用的记录器

答案 2 :(得分:0)

作为上述答案的替代,这可以仅在StructureMap中解决(我相信适用于问题中使用的SM版本)。您可以通过在注册表中包含以下内容来告诉StructureMap如何构建MyClass

For<MyClass>().Use(x => new MyClass(x.GetInstance<ILog>("Logger1"), x.GetInstance<ILog>("Logger2")));