Using LogManager.GetLogger with Unity

匿名 (未验证) 提交于 2019-12-03 02:52:02

问题:

Given this class:

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

I'd like to configure Unity to inject ILog. That's easy:

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

But I'd like to make Unity call LogManager.GetLogger with the type of the parent type being resolved.

This is close:

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

But t in this case is the type being resolved (ILog), not the type that the object is being resolved for (Foo).

I know I can do this:

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

But I don't want to have to add that crazy declaration every time I register an object.

I know this can be done in Autofac, and I know the Real Answer is not to use Unity in the first place, but can this be done? :)

回答1:

Unity might not give you all the goodies some of the other containers offer but I have yet to find a feature you can't easily add.

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

You can find the source code for the TrackingExtension here. Its located in the TecX.Unity project folder.



回答2:

If you want a DI container to return you a logger based on the class’ type information, then put the type information into the public interface so the DI container can see it. It removes the need for any container specific override features and then it won’t matter if you are using Unity or AutoFac.

Someone that knows the log4net object model well might be able to give you a more efficient implementation, but try something like this:

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


回答3:

This seems like a very clean approach: https://github.com/roblevine/UnityLoggingExtensions



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!