Я использую log4net в качестве каркаса ведения журнала и Unity в качестве моего контейнера IoC.Затем я установил пакет Unity.log4net nuget.Я сталкиваюсь с проблемой с именем регистратора, когда я начинаю использовать именованные регистрации.Я использую именованные регистрации, чтобы включить конструктор внедрения IEnumerable с T.
Приведенный ниже код является очень простой программой, которая показывает мою проблему.
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);
Я что-то здесь упускаю?