场景:我们做项目的时候常常会引用第三方日志框架来帮助我们记录日志,日志组件的用途主要是审计、跟踪、和调试。就说我最常用的日志组件log4net吧,这个在.NET同行当中应该算是用得非常多的一个日志组件了。
而同时,我们又经常使用IoC技术,来降低我们项目之间、模块之间的耦合度,比如我现在在用的Microsoft.Practices.Unity(当然Autofac也是非常好用的)。
我们很清楚的知道log4net的优点,配置非常简单又非常完善,它能提供不同的日志级别、记录器、组织形式……
比如说 :
var log = LogManager.GetLogger("User");
但是当我们使用IoC注入日志记录器对象的时候,就犯难了,我想给不同的类注入不同的日志记录器,这样方便我选择性的配置哪些类、哪些级别的日志需要输出。
如:
public class UserService { public UserRepository Repository { get; } public ILog Log { get; set; } public UserService(UserRepository repository,ILog log) { Repository = repository; Log = log; } } public class UserRepository { public ILog Log { get; } public UserRepository(ILog log) { Log = log; } }
我想要的是给UserRepository注入 LogManager.GetLogger(typeof(UserRepository));
我想要的是给UserService注入 LogManager.GetLogger(typeof(UserService));
这样在UserRepository、UserService中写日志的时候,是分别写入不同的日志记录器,我可以很方便的控制收集哪些日志。
该怎么做呢?
找了很多资料,都没有找到Microsoft.Practices.Unity如何访问解析依赖时的上下文,我希望上下文中能找到请求ILog的对象是什么类型。
终于还是在Microsoft.Practices.Unity的源代码讨论区里面找到了解决方案,遂封装一下,简化类似操作。测试代码如下:
using NUnit.Framework; using System; using System.Diagnostics; using System.Threading.Tasks; using log4net; namespace Microsoft.Practices.Unity.Tracking.Tests { [TestFixture] public class TrackingInjectionFactoryTests { public IUnityContainer Container { get; set; } [SetUp] public void Initialize() { Trace.Listeners.Add(new ConsoleTraceListener()); Container = new UnityContainer(); Container.Tracking(); Container.RegisterType<UserService>(); Container.RegisterType<ILog>(new TrackingInjectionFactory((container, context, policy) => LogManager.GetLogger(policy.RequestType?.Name ?? "null"))); } [Test] public void TrackingInjectionFactoryTest() { Parallel.For(0, 1, new ParallelOptions { MaxDegreeOfParallelism = 10 }, i => { var userService = this.Container.CreateChildContainer().Resolve<UserService>(); Trace.WriteLine(userService.Log.Logger.Name, "UserService.Log.Logger.Name"); Trace.WriteLine(userService.Repository.Log.Logger.Name, "UserService.Repository.Log.Logger.Name"); }); var action = new Action(() => { var log = this.Container.CreateChildContainer().Resolve<ILog>(); Trace.WriteLine(log.Logger.Name, "Logger.Name"); }); action(); var asyncResult = action.BeginInvoke(null, null); action.EndInvoke(asyncResult); } public class UserService { public UserRepository Repository { get; } public ILog Log { get; set; } public UserService(UserRepository repository, ILog log) { Repository = repository; Log = log; } } public class UserRepository { public ILog Log { get; } public UserRepository(ILog log) { Log = log; } } } }
源代码地址:https://github.com/echofool/Microsoft.Practices.Unity.Tracking
原谅我很懒,都不想解释太多...