Застрял, пытаясь заставить Log4Net работать с Dependency Injection - PullRequest
2 голосов
/ 10 октября 2009

У меня есть простое тестовое приложение winform, которое я использую, чтобы попробовать некоторые вещи для внедрения зависимостей Log4Net.

В моем проекте Services я создал простой интерфейс: -

public interface ILogging
{
    void Debug(string message);

    // snip the other's.
}

Тогда мой конкретный тип будет использовать Log4Net ...

public class Log4NetLogging : ILogging
{
    private static ILog Log4Net
    {
        get { return LogManager.GetLogger(
                       MethodBase.GetCurrentMethod().DeclaringType); }
    }

    public void Debug(string message)
    {
        if (Log4Net.IsDebugEnabled)
        {
            Log4Net.Debug(message);
        }
    }
}

Пока все хорошо. Там нет ничего сложного.

Теперь, в другом проекте (и, следовательно, namesapce), я пытаюсь использовать это ...

public partial class Form1 : Form
{  
    public Form1()
    {
        FileInfo fileInfo = new FileInfo("Log4Net.config");
        log4net.Config.XmlConfigurator.Configure(fileInfo);
    }

    private void Foo()
    {
        // This would be handled with DI, but i've not set it up 
        // (on the constructor, in this code example).
        ILogging logging = new Log4NetLogging(); 
        logging.Debug("Test message");
    }
}

Хорошо, тоже довольно просто. Я жестко запрограммировал экземпляр ILogging, но обычно это зависимость, внедряемая через конструктор. В любом случае, когда я проверяю эту строку кода ...

return LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

значение типа DeclaringType относится к пространству имен Service , а не к типу Form (т.е. X.Y.Z.Form1), который фактически вызвал метод.

Не передавая метод типа INTO в качестве другого аргумента, есть ли в любом случае отражение для определения метода real, который его вызвал?

Ответы [ 2 ]

1 голос
/ 13 июня 2012

дополнительный ответ, который может помочь кому-то
Следуя предложению Стива, я изменил свою реализацию службы ведения журналов, чтобы в ней был конструктор, который принимает тип, т.е. аргумент типа для предоставления в Метод регистрации, указанный в интерфейсе ILogger

public class MyLogging_Service : IMyLogging_Service
{
    private Type _declaringType;
    private ILog _log;
    private ILog Log { get { return _log; } }

    public MyLogging_Service(Type p_Val)
    {
        _declaringType = p_Val;
        _log = LogManager.GetLogger(p_Val);
    }

    public void LogInfo(string p_Msg)
    {
        Log.Logger.Log(_declaringType, Level.Info, p_Msg, null);
    }

...

}

фактическое использование

public class Service1 : IService1
{
    // declared as a property
    IMyLogging_Service MyLoggingService { get; set; }

}

до этого я использовал StructureMap для автоматического заполнения этого свойства, используя сеттер впрыска
см. ссылка

в моем загрузчике инъекций зависимостей я использовал следующее утверждение

FillAllPropertiesOfType<IMyLogging_Service>().TheDefault.Is
                .ConstructedBy(context => new MyLogging_Service(context.ParentType));

Подведем итоги
1. создал класс для реализации ведения журнала, используя конструктор, который принимает тип, используемый для указания аргумента callerStackBoundaryDeclaringType в реализации метода Log
2. создал свойство службы ведения журнала для класса, который должен иметь функцию ведения журнала
3. включил код в загрузчик инъекций зависимостей, чтобы заполнить свойство родительским типом, используя контекстную переменную StructureMap

Кстати, в случаях, когда в вашем коде нет необходимости в DI, вы можете написать такой код

new MyLogging_Service(this.GetType())
0 голосов
/ 10 октября 2009

Чтобы получить объект MethodInfo, который вызывает конкретный метод, вам нужно проверить стек вызовов. Это можно сделать с помощью класса StackTrace следующим образом.

using System.Diagnostics;
using System.Reflection;

public class Log4NetLogging : ILogging
{
    private ILog GetLogForStackFrame(StackFrame frame)
    {
        return LogManager.GetLogger(frame.GetMethod().DeclaringType);
    }

    public void Debug(string message)
    {
        ILog log = GetLogForStackFrame(new StackTrace().GetFrame(0));
        if (log.IsDebugEnabled)
        {
            log.Debug(message);
        }
    }
}

Кстати, я бы рассмотрел изменение вашего интерфейса, чтобы он принимал Type объекта, который будет использовать абстрактный журнал. Я понимаю, что вы не хотите этого делать, но получение стека вызовов во время выполнения является дорогостоящей операцией, и ее нужно будет выполнять каждый раз, когда вы вызываете ILogging.Debug.

...