我正在使用 log4net 作为日志记录框架,并使用 Unity 作为我的IoC容器。接下来,我安装了 Unity.log4net nuget软件包。当我开始使用命名注册时,记录器名称出现问题。我使用命名注册启用T的IEnumerable的构造函数注入。
下面的代码是一个非常简单的程序,它显示了我的问题。
using Container.Activities;
using log4net;
using Unity;
using Unity.log4net;
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
namespace Container
{
class Program
{
static void Main(string[] args)
{
UnityContainer container = new UnityContainer();
container.AddNewExtension<Log4NetExtension>();
container.RegisterType<IActivity, ActivityA>(nameof(ActivityA));
container.RegisterType<IActivity, ActivityB>(nameof(ActivityB));
container.RegisterType<IActivityExecutor, ActivityExecutor>();
var logger = LogManager.GetLogger("Test application");
logger.Info("Application started.");
container.Resolve<IActivityExecutor>().Execute();
logger.Info("Application stopped.");
}
}
}
我创建了一个Activity接口,并将对该接口进行多种实现。
namespace Container.Activities
{
public interface IActivity
{
void Execute();
}
}
在此示例中,我只有两个实现,即活动A和B。这两个实现都需要将log4net.ILog实现注入到构造函数中。
using log4net;
namespace Container.Activities
{
public class ActivityA : IActivity
{
private readonly ILog _logger;
public ActivityA(ILog logger)
{
_logger = logger;
}
public void Execute()
{
_logger.Info($"Hello, I am {nameof(ActivityA)}.");
}
}
}
活动B:
using log4net;
namespace Container.Activities
{
public class ActivityB : IActivity
{
private readonly ILog _logger;
public ActivityB(ILog logger)
{
_logger = logger;
}
public void Execute()
{
_logger.Info($"Hello, I am {nameof(ActivityB)}.");
}
}
}
在多个IActivity实例旁边,我有一个IActivityExecutor接口。
namespace Container.Activities
{
public interface IActivityExecutor
{
void Execute();
}
}
Activity Executor实例应执行所有已注册的IActivity实例。接下来,它注入了自己的ILog实例,因此它也可以写入日志文件。
using log4net;
using System.Collections.Generic;
using System.Linq;
namespace Container.Activities
{
public class ActivityExecutor : IActivityExecutor
{
private readonly ILog _logger;
private readonly IEnumerable<IActivity> _activities;
public ActivityExecutor(ILog logger, IEnumerable<IActivity> activities)
{
_logger = logger;
_activities = activities;
}
public void Execute()
{
_logger.Info($"About to process {_activities.Count()}.");
foreach (var activity in _activities)
{
activity.Execute();
}
}
}
}
我的日志文件中的输出如下所示。请注意,ActivityA和ActivityB都以记录器名称ActivityExecutor结尾在日志文件中。
2019-03-19 14:43 [Test application] [1] INFO - Application started.
2019-03-19 14:43 [Container.Activities.ActivityExecutor] [1] INFO - About to process 2.
2019-03-19 14:43 [Container.Activities.ActivityExecutor] [1] INFO - Hello, I am ActivityA.
2019-03-19 14:43 [Container.Activities.ActivityExecutor] [1] INFO - Hello, I am ActivityB.
2019-03-19 14:43 [Test application] [1] INFO - Application stopped.
此输出不是我期望的。我希望看到下面的日志。因此,每个活动都使用自己的名称进行记录。
2019-03-19 14:43 [Test application] [1] INFO - Application started.
2019-03-19 14:43 [Container.Activities.ActivityExecutor] [1] INFO - About to process 2.
2019-03-19 14:43 [Container.Activities.ActivityA] [1] INFO - Hello, I am ActivityA.
2019-03-19 14:43 [Container.Activities.ActivityB] [1] INFO - Hello, I am ActivityB.
2019-03-19 14:43 [Test application] [1] INFO - Application stopped.
此问题的根本原因似乎与在Unity容器中使用命名注册有关。如果我在ActivityExecutor的构造函数中添加另一个接口参数,并将其放在ILog参数之前,则在日志文件中使用该组件的名称。
我可以从该程序的所有构造函数中删除ILog,而是调用LogManager以获取带有每个组件名称的记录器。但是,我更喜欢在需要时注入ILog接口,并使用Unity.log4net软件包。
_logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
我在这里想念东西吗?