場景:我們做項目的時候常常會引用第三方日志框架來幫助我們記錄日志,日志組件的用途主要是審計、跟蹤、和調試。就說我最常用的日志組件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
原諒我很懶,都不想解釋太多...