Неожиданное поведение Log4NetExtension в сочетании с зарегистрированным IEnumerable <T>в контейнере Unity - PullRequest
1 голос
/ 19 марта 2019

Я использую 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);

Я что-то здесь упускаю?

...