在Unity中使用LogManager.GetLogger

时间:2011-12-20 14:19:39

标签: log4net unity-container

鉴于此课程:

class Foo
{
    readonly ILog log;

    public Foo(ILog log)
    {
        this.log = log;
    } 

    ...
}

我想配置Unity注入ILog。这很简单:

container.RegisterInstance<ILog>(LogManager.GetLogger(typeof(XYZ)));

但是我想用正在解析的父类型的类型调用Unity LogManager.GetLogger

这很接近:

container.RegisterType<ILog>(new InjectionFactory((c, t, s) => LogManager.GetLogger(t)));

但在这种情况下t是要解析的类型(ILog),而不是正在为其解析对象的类型(Foo)。

我知道我可以这样做:

container.RegisterType<Foo>(new InjectionFactory(c => new Foo(LogManager.GetLogger(typeof(Foo)));

但是我不希望每次注册对象时都要添加那个疯狂的声明。

我知道这可以在Autofac中完成,我知道真正的答案不是首先使用Unity,但这可以做到吗? :)

3 个答案:

答案 0 :(得分:6)

Unity可能不会给你一些其他容器提供的好东西,但我还没有找到你不能轻易添加的功能。

var container = new UnityContainer();
container.AddNewExtension<TrackingExtension>();
container.RegisterType<ILog>(
  new InjectionFactory((ctr, type, name) =>
    {
      var tracker = ctr.Resolve<ITracker>();
      var parentType = tracker.CurrentBuildNode.Parent.BuildKey.Type;
      return LogManager.GetLogger(parentType);
    }));
var sut = container.Resolve<UsesLog>();
Assert.AreEqual(typeof(UsesLog), sut.Log.Type);

您可以找到 TrackingExtension here的源代码。它位于 TecX.Unity 项目文件夹中。

答案 1 :(得分:3)

如果您希望DI容器根据类的类型信息返回一个记录器,则将类型信息放入公共接口,以便DI容器可以看到它。它不需要任何特定于容器的覆盖功能,如果您使用Unity或AutoFac则无关紧要。

非常了解log4net对象模型的人可能能够为您提供更高效的实现,但尝试这样的事情:

using System;
using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnityLoging
{
    public interface ILog<T> : log4net.ILog
    { }

    public class MyLogger<T> : log4net.Core.LogImpl, ILog<T>
    {
        public MyLogger() : base(log4net.LogManager.GetLogger(typeof(T).Name).Logger)
        { }
    }

    public class ClassToLog
    {
        private readonly log4net.ILog log;

        public ClassToLog(ILog<ClassToLog> log)
        {
            this.log = log;
        }

        public void LogMe()
        {
            log.Debug("Got here");
        }
    }

    [TestClass]
    public class TestClass
    {
        [TestMethod]
        public void GenericLogRegistrationTest()
        {
            log4net.Config.XmlConfigurator.Configure();
            IUnityContainer container = new UnityContainer();
            container.RegisterType(typeof(ILog<>), typeof(MyLogger<>));

            ClassToLog c = container.Resolve<ClassToLog>();
            c.LogMe();

            log4net.LogManager.Shutdown();
        }
    }
}

答案 2 :(得分:2)

这似乎是一种非常干净的方法:https://github.com/roblevine/UnityLoggingExtensions