我如何将StructureMap与同一接口的2个不同对象(log4net记录器)连接起来?



我有一个名为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");
    }
 }

引入DI,使用StructureMap(使用v3.0.3),我将使记录器实例成员,并将它们注入构造函数,如下所示:公共类MyClass{private readonly ilogloger1;private readonly 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");

Doing this让我空(未配置的)记录器)。用Add()替换Use()给了我一个异常,因为没有为ILog注册默认实例。

有人知道我该怎么做吗?

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

我最终做了以下事情:我按照Rob的建议创建了两个接口:ILogger1ILogger2。由于两者具有相同的API,因为我需要相同的类型的功能,它们都继承自相同的接口-尽管不是 log4net.ILog,正如Steven的建议:

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();

一切都很好。所以,感谢史蒂文和罗布的建议。我真的学到了一些东西。我希望我能不止一次地为一个答案和一个回应投票。

总结一下,我:

  • 为每种记录器创建了单独的界面(甚至现在听起来很直观)。
  • 为记录器接口创建了一个基本接口,因为对于我的需求它们具有相同的API (YMMV)
  • 创建一个实现两个接口的具体记录器适配器,因为它适合我的需求(再次YMMV)
  • 由于上述原因,共享接口API的实现
  • 注册每个接口来创建一个具体的记录器,并在构造函数中传递不同的类型
  • 用log4net配置具体的记录器,使用工厂方法来确定使用哪个记录器

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

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

相关内容

  • 没有找到相关文章

最新更新