Как внедрить логические реализации Log4Net ILog с использованием Unity 2.0

В конечном счете это связано с настройкой log4Net, но в общем случае проблема не связана с конкретным протоколом.

В общем, я пытаюсь понять, как это сделать в Microsoft Unity 2.0, что-то эквивалентное тому, что получается с помощью Castle.Facilities.Logging.LoggingFacility. А именно, способность объявлять зависимость от регистратора и инициализировать логгер с типом объекта, в который он вводится.

В духе теста стоит тысяча слов, вот что мне нужно:

class Logger_IOC_Tests
{
    //[Test] 
    public void Logger_should_be_initialized_with_the_type_of_the_object_that_is_using_it()
    {
        var container = new UnityContainer();
        /* Configuration Magic probably involiving registering either 
            * a custom IDependencyResolverPolicy or BuilderStrategy
            * goes here...
            */
        container.RegisterType<LoggerUser>(new ContainerControlledLifetimeManager());

        var user = container.Resolve<LoggerUser>();

        Assert.True(user.Logger.GetUserType() == user.GetType());
    }
}

interface ILogger
{
    Type GetUserType();
}

class Logger : ILogger
{
    private readonly Type _type;

    public Logger(Type type)
    {
        _type = type;
    }

    public Type GetUserType()
    {
        return _type;
    }
}

class LoggerUser
{
    public readonly ILogger Logger;

    public LoggerUser(ILogger logger)
    {
        Logger = logger;
    }
}

Ответы

Ответ 1

Я не знаю, если это то, что вы ищете, но я видел это несколько месяцев назад, и мне напомнили об этом, когда я увидел ваш вопрос. Я не использовал Unity, поэтому я не могу сравнить то, что вы разместили, с тем, что находится по ссылке. Надеюсь, вам это будет полезно:

http://davidkeaveny.blogspot.com/2011/03/unity-and-log4net.html

Ответ 2

Я пытаюсь добиться того же результата, что и возможность вставлять правильно настроенные экземпляры ILog в зависимость, используя инъекцию конструктора с Unity.

В конце концов, я написал собственное расширение единства "log4net", чтобы сделать именно это (частично вдохновленный сообщением в блоге, которое написал другой ответчик, Кеннет Балтринич).

Это позволяет вам зарегистрировать расширение один раз с помощью Unity:

var container = new UnityContainer();
container.AddNewExtension<Log4NetExtension>();

а затем введите правильный экземпляр регистратора ILog:

public class MyClass
{
    private readonly ILog logger;

    public MyClass(ILog logger)
    {
        this.logger = logger;
    }
}

Расширение можно найти здесь:

https://github.com/roblevine/UnityLoggingExtensions

Дополнительная информация здесь: http://blog.roblevine.co.uk/net/using-log4net-with-unity/

EDIT теперь доступен как пакет NuGet

Ответ 3

После нескольких часов работы в исходном коде Unity я придумал следующее решение. Тем не менее, я бы предпочел найти способ установки соответствующего зависимого преобразователя на основе разрешаемого типа, а не переопределения политики селектора конструктора по умолчанию. Во-первых, поскольку я ранее переопределял селектор конструктора по умолчанию для других целей. В другом случае это решение обрабатывает только зависимости, которые вводятся через конструктор. Для полного охвата нужно было бы переопределить свойства и методы выбора по умолчанию, как я полагаю. Для себя мне нужны только конструкторы.

class Logger_IOC_Tests
{
    [Test] 
    public void Logger_should_be_initialized_with_the_type_of_the_object_that_is_using_it()
    {
        var container = new UnityContainer();
        container.AddNewExtension<LoggingExtension>();
        container.RegisterType<LoggerUser>(new ContainerControlledLifetimeManager());
        var user = container.Resolve<LoggerUser>();

        Assert.True(user.Logger.GetUserType() == user.GetType());
    }
}

class LoggingExtension : UnityContainerExtension
{
    protected override void Initialize()
    {
        Context.Policies.SetDefault(typeof(IConstructorSelectorPolicy), new LoggingConstructorSelectorPolicy()); 
    }
}

public class LoggingConstructorSelectorPolicy : DefaultUnityConstructorSelectorPolicy
{
    protected override IDependencyResolverPolicy CreateResolver(ParameterInfo parameter)
    {
        return parameter.ParameterType == typeof(ILogger) 
                   ? new LoggerResolverPolicy(parameter.Member.DeclaringType) 
                   : base.CreateResolver(parameter);
    }
}

class LoggerResolverPolicy : IDependencyResolverPolicy
{
    private readonly Type _dependantType;

    public LoggerResolverPolicy(Type dependantType)
    {
        _dependantType = dependantType;
    }

    public object Resolve(IBuilderContext context)
    {
        return new Logger(_dependantType);
    }
}

Ответ 4

Вышеупомянутое расширение работает хорошо, но для пользователей MVC5 требуется больше информации о конфигурации. Вот шаги, использующие единство.

Добавьте следующую строку вверху вашего класса startup.cs над пространством имен.

[сборка: log4net.Config.XmlConfigurator(ConfigFile = "Web.config", Watch = true)]

В вашем методе global.asax application_startup добавьте следующую информацию:

log4net.Config.XmlConfigurator.Configure(new FileInfo(Server.MapPath("~/Web.config")));

Остальная конфигурация контейнера единства должна быть такой:

container.AddNewExtension<Log4NetExtension>();

Убедитесь, что у вас есть appender, добавленный в ваш web.config. Это должно быть связано с тем, чтобы это правильно работало. Удачи