【问题标题】:Using structuremap with log4net wrapper将结构映射与 log4net 包装器一起使用
【发布时间】:2009-12-21 21:57:36
【问题描述】:

我有如下界面:

public interface ILogger
{
    void Debug(string message, params object[] values);
    void Info(string message, params object[] values);
    void Warn(string message, params object[] values);
    void Error(string message, params object[] values);
    void Fatal(string message, params object[] values);
}

以及以下实现:

public class Log4netLogger : ILogger
{
    private ILog _log;

    public Log4netLogger(Type type)
    {
        _log = LogManager.GetLogger(type);
    }

    public void Debug(string message, params object[] values)
    {
        _log.DebugFormat(message, values);
    }

    // other logging methods here...

}

我的想法是使用结构映射来实例化 Log4netLogger 类,并使用执行日志记录的类的类型。但是,我一生都无法弄清楚如何将调用类的类型传递给结构映射,以便可以将其传递给日志实现的构造函数。任何有关如何做到这一点(或更好的方法)的建议将不胜感激。

【问题讨论】:

    标签: inversion-of-control structuremap


    【解决方案1】:

    我们在 log4net 周围使用类似的 ILogger 包装器,并且通常使用构造函数注入。我们使用拦截器作为负责创建 Logger 的工厂方法。这是我们用于日志记录设置的典型注册表。

    public class CommonsRegistry : Registry
    {
        public CommonsRegistry()
        {
            For<ILogger>()
                .AlwaysUnique()
                .TheDefault.Is.ConstructedBy(s =>
                {
                    if (s.ParentType == null)
                        return new Log4NetLogger(s.BuildStack.Current.ConcreteType);
    
                    return new Log4NetLogger(s.ParentType);
                });
    
            var applicationPath = Path.GetDirectoryName(Assembly.GetAssembly(GetType()).Location);
            var configFile = new FileInfo(Path.Combine(applicationPath, "log4net.config"));
            XmlConfigurator.ConfigureAndWatch(configFile);
        }
    }
    

    当依赖于具体类型时,父类型空检查是必要的。

    其余的是可选的 log4net 设置。

    我喜欢这种设置的一点是能够使用空记录器进行单元测试。

    【讨论】:

    • 有趣,我得试试这个。谢谢!
    • 这确实很有趣。我也看到了你对我的回答的评论。如果 ctor 依赖项是调用类类型之外的任何内容,这会起作用吗?希望看到有关特定于上下文的 ctor 依赖项的博客文章,因为这必须是有关使用 DI 框架的第 1 个最常见的问题。
    • 另外,我正在努力解决这个解决方案是否会使依赖关系变得不那么明确。如果构造确实需要工厂,那么将工厂“隐藏”在配置代码中,而不是明确地依赖抽象工厂是不是一个好主意? (我的意思是这是一个理论问题,不一定是 Chris 或日志记录本身的最佳解决方案)。
    • 不确定我是否理解您的 ctor 问题。当您将依赖项放入构造函数时,StructureMap 将确保在创建此类实例时将其注入到此类实例中。在每种类型的依赖关系图中,每种类型都是如此。 Jeremy 刚刚发布了关于嵌套容器的新功能,它可以让您控制上下文依赖关系:codebetter.com/blogs/jeremy.miller/archive/2010/01/06/…
    • 这种性质的工厂实际上是配置,因此将它存在于我们放置应用程序大部分配置的注册表中感觉很好。如果您担心创建一个静态工厂方法。当使用 IoC 容器时,使用过于简单的工厂类来描述如何创建类型感觉很愚蠢。因为这就是 IoC 的用途。
    【解决方案2】:

    如果类型参数是特定于上下文的,我认为这不会像所示的那样工作。如果您需要在构造函数中传递特定于上下文的内容,您可能必须创建一个返回 ILogger 实例的工厂接口和实现:

    public interface ILoggerFactory
    {
        ILogger Create(Type type);   
    }
    
    public class LoggerFactory : ILoggerFactory
    {
        public ILogger Create(Type type)
        {
            return new Log4netLogger(type);
        }
    }
    

    也许可以引导 StructureMap 以根据类型提供您想要的实例,但前提是您事先知道的类型数量有限。

    【讨论】:

    【解决方案3】:

    我真的需要改掉自己回答问题的习惯,但是对于那些遇到它的人来说,这就是答案。

    return ObjectFactory.With(type).GetInstance<T>();
    

    我实际上有一个结构映射的包装器(以避免将结构映射依赖项暴露给我的应用程序),如下所示:

    public static class ServiceManager
    {
        public static T Get<T>()
        {
            return ObjectFactory.GetInstance<T>();
        }
    
        public static T Get<T>(Type type)
        {
            return ObjectFactory.With(type).GetInstance<T>();
        }
    }
    

    任何时候在代码中我需要一个记录器,我都会调用以下代码:

    ServiceManager.Get<ILogger>(GetType()).Info("Logging page view...");
    

    【讨论】:

    • 我实际上不认为将记录器视为全局服务有什么问题(因为它通常是横切的),但这确实会创建对您的 ServiceManager 的静态依赖。我并不是说您的解决方案是错误的(远非如此),但听起来有点像它可能倾向于全球服务定位器“反模式”。本质上,您对 ILogger(或 ILoggerFactory)的依赖已(或可能)不再明确。
    • 有趣点菲尔。我不确定替代方案是什么(关于 IoC 的架构建议确实很少)。在我的例子中,该类是一个 HttpHandler,它需要访问它从 ServiceManager 请求的 ILogger。我还能如何实现?
    • 我完全同意架构建议很少,恕我直言,您的问题是人们在开始使用 DI 框架时遇到的最常见的障碍。创建一个抽象工厂是我想出的最佳答案,而且我经常使用 StructureMap (ObjectFactory.GetInstance) 来实现该工厂,这样链下游的依赖关系仍然可以由容器管理。这可能不是完美,但至少依赖关系是明确的。
    • 嗯...因为代码在 HttpHandler 中,所以我不能真正使用工厂。也许我应该将代码移动到不同的类,并使用 IoC 容器来加载该类,并将 ILogger 作为构造函数中的显式依赖项。那会更合适吗?
    • @Chris:为了将 DI 转换为 HttpHandler,您可以使用自定义的 PageHandlerFactory。请参阅aspnetresources.com/articles/ioc_and_di_with_web_forms.aspx 了解更多信息
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-20
    • 1970-01-01
    • 1970-01-01
    • 2017-07-02
    相关资源
    最近更新 更多