【问题标题】:Default dependency injection? [duplicate]默认依赖注入? [复制]
【发布时间】:2014-03-13 10:51:41
【问题描述】:

我需要在整个域中记录很多东西,因此我的大多数域和应用程序服务都依赖于日志记录实现。假设我创建了这个小合约:

public interface ILogger {

    void Info(string message);

}

太好了。现在我实现了一个基于 log4net 的基础设施服务:

public class Log4NetProxy : ILogger {

    private ILog _logger = LogManager.GetLogger();

    public void Info(string message) {
        _logger.Info(message);
    }
}

但是,由于我的大多数类都具有其他依赖项而不仅仅是记录器,因此我越来越接近于构造函数注入模式..

public class MyService : IMyService {

    public MyService(ILogger logger, IRepository repo, IAlsoNeedSettings settings) {

    }

}

如何避免注入诸如设置或日志记录等基本核心需求,而只关注我真正需要的依赖项?属性注入?服务门面?静态日志工厂?

【问题讨论】:

  • 看面向切面编程
  • private ILog _logger = LogManager.GetLogger(); 是服务定位器,而不是注入器。我使用 Autofac,但我仍然没有找到一种很好的方法来注入不是为从头开始(构造函数或属性/字段)注入而设计的对象图;通常有一些“根”需要集成,然后如果存在差距,则可能需要公开容器以进行直接/SL 解析(至少在图表可以再次开始自行解析之前)。

标签: c# dependency-injection domain-driven-design ninject constructor-injection


【解决方案1】:

[Rant+关于拦截器的代码已删除,因为这不是你需要的:)]

我发现属性注入通常是可行的方法,因为它避免了通常不太有趣的样板代码

...我将构造函数值中的无数个 ISomething 分配给 属性...

我不知道如何在 Autofac 中使用它(我主要使用 Castle.Windsor),但我推荐它作为一种低维护和避免构造函数膨胀的好方法

编辑:显然,Mark Seemann 提到的问题提到拦截是处理这些情况的一种有效方式,所以我将放回我原来的咆哮+代码。我不确定它是否符合他所指的内容,但它可能会给你一些想法


我真的很喜欢 Castle-Windsor 拦截系统,它有点像面向方面的编程,你将解析的组件包装在拦截器中,然后根据参数、方法名称等决定如何操作

这是我的拦截记录器的示例:

public class LoggingInterceptor: IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        using (Tracer t = new Tracer(string.Format("{0}.{1}", invocation.TargetType.Name, invocation.Method.Name)))
        {
            StringBuilder sb = new StringBuilder(100);
            sb.AppendFormat("IN (", invocation.TargetType.Name, invocation.Method.Name);
            sb.Append(string.Join(", ", invocation.Arguments.Select(a => a == null ? "null" : DumpObject(a)).ToArray()));
            sb.Append(")");
            t.Verbose(sb.ToString());

            invocation.Proceed();

            sb = new StringBuilder(100);
            sb.AppendFormat("OUT {0}", invocation.ReturnValue != null ? DumpObject(invocation.ReturnValue) : "void");
            t.Verbose(sb.ToString());
        }
    }

    private string DumpObject(object argument)
    {
        // serialize object
    }
}

然后在设置期间注册此记录器拦截器并将其应用于 WCF 服务中的有趣类:

// register interceptors
_container.Register(
    Classes.FromAssemblyInThisApplication()
    .BasedOn<IInterceptor>()
    .WithServiceBase()
    .Configure(c => c.Named(c.Implementation.Name))
);

// apply them
_container.Register
(
    Component.For<IService>()
        .ImplementedBy<ServicesImplementation.Service>()
        .Named("Service")
        .LifestylePerWcfOperation()
        .Interceptors("LoggingInterceptor")
);

您可以考虑拦截对需要 ILogger 的方法或具有 ILogger 属性的类的调用,并将其从拦截器中注入。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-21
    • 2018-03-23
    • 2011-10-27
    • 1970-01-01
    • 1970-01-01
    • 2019-02-25
    • 2011-06-08
    相关资源
    最近更新 更多