1

使用Simple Injector我在记录器中遇到了一个共同的主题,我在记录器注入到的服务对象的构造函数中设置记录器名称。当服务写入日志时,可以通过此日志名轻松识别。

由于LogNames将为每个服务设置,因此每个对象图请求的记录器应该是唯一的。

我想在构建图表时自动执行此操作,我已经四处寻找,ExpressionBuilt()但我正在努力,但还没有得到我想要的工作 - 这甚至可能(或者想做的事情)?

我的构造函数代码如下(此LogName属性设置代码在我的大多数服务中都很常见)。

谢谢,

克里斯

public interface ILogger
{
    void LogMessage(string message, LogLevel level,
        ILoggableCompany company = null);

    string LogName {get; set; }
}

public BusinessUnitService
{
    private readonly IUnitOfWork unitOfWork;
    private readonly ILogger logger;

    public BusinessUnitService(IUnitOfWork unitOfWork, 
        ILogger logger)
    {
        this.unitOfWork = unitOfWork;
        this.logger = logger;

        // it would be great if we could take away this 
        // line and set it automatically
        this.logger.LogName = this.GetType().ToString();
    }
}
4

1 回答 1

1

这个设计看起来有点像Logger<T>log4net 的设计,T记录器创建的类将在哪里。虽然我无法查看您的设计,但我想知道:您是不是记录太多?

如果你真的需要这样做,至少LogName从界面中删除该属性ILogger,因为它在那里没有业务。这意味着您必须从构造函数中删除设置此属性的代码,这绝对没问题,因为这是到处重复的代码。

您正在尝试做的是基于上下文的注入,这不是开箱即用的支持,但是 Simple Injector wiki 包含一个Context Bases Injection 部分,该部分解释了如何添加此支持。该文档页面甚至使用了一个Logger<T>示例:-)

使用wiki 引用的扩展方法,您可以执行以下操作:

public interface ILogger
{
    void LogMessage(string message, LogLevel level,
        ILoggableCompany company = null);

    // No LogName property here. Keep it clean.
}

public class LoggerImpl : ILogger
{
    public void LogMessage(string message, 
        LogLevel level, ILoggableCompany company)
    {
       // implementation
    }

    // Property only part of the implementation.
    public string LogName {get; set; }
}

// The parent contains information about the type in 
// which ILogger is injected.
container.RegisterWithContext<ILogger>(parent =>
{
    // Retrieve a new LoggerImpl instance from the container 
    // to allow this type to be auto-wired.
    var logger = container.GetInstance<LoggerImpl>();

    // ImplementationType is null when ILogger is
    // requested directly (using GetInstance<ILogger>())
    // since it will have no parent in that case.
    if (parent.ImplementationType != null)
    {
        // Set the LogName with the name of the class 
        // it is injected into.
        logger.LogName = parent.ImplementationType.Name;
    }

    return logger;
});

// Register the LoggerImpl as transient. This line is
// in fact redundant in Simple Injector, but it is important
// to not accidentally register this type with another
// lifestyle, since the previous registration depends on it
// to be transient.
container.Register<LoggerImpl>();

因为这通过挂钩BuiltExpression事件和重新连接表达式来工作,以这种方式解析实例几乎与使用Func<T>工厂方法注册一样快。

于 2012-06-22T07:33:22.677 回答