Stuck trying to get Log4Net to work with Dependency Injection

I have a simple winform test application that I am using to try out some of the Log4Net dependency injection stuff.

I made a simple interface in my "Services" project: -

public interface ILogging
{
    void Debug(string message);

    // snip the other's.
}

      

Then my concrete type would be using 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);
        }
    }
}

      

So far so good. There is nothing difficult here.

Now, in another project (and therefore namesapce), I am trying to use this ...

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");
    }
}

      

Ok .. pretty basic too. I have hardcoded the ILogging instance, but this is usually a constructor dependency. Anyway, when I check this line of code ...

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

      

the type value DeclaringType

is relative to the service namespace, not the form type (that is, XYZForm1) that actually named this method.

Without passing a method of type INTO as another argument, is reflection still used to define the method real

that called it?

+2


source to share


2 answers


To get the object MethodInfo

that calls a particular method, you need to examine the call stack. This can be accomplished with a class StackTrace

as follows.

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);
        }
    }
}

      



On the other hand, I would like to consider modifying your interface to accept an Type

object that abstract log will use. I understand that you don't want to do this, but populating the call stack at runtime is an expensive operation and must be done every time you call ILogging.Debug

.

0


source


additional answer that might help someone following Steve's suggestion, I changed my implementation of the logging service to have a constructor that takes a type, like a type argument to supply to the Log method specified in the ILogger interface

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);
    }

...

}

      

actual use

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

}

      

before that i used StructureMap to auto populate this property using setter injection
see link



in my load dependency loading buffer i used the following statement

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

      

to repeat
1.created a class for logging using a constructor that takes a type that will be used to specify the callerStackBoundaryDeclaringType argument in the implementation of the Log method 2.created a
logging service property for the class that requires logging functionality 3.included
code in the loader dependency injection to populate the property with the parent type using the context variable StructureMap

btw in cases in your code where DI is not needed then you can write code like this

new MyLogging_Service(this.GetType())

      

+1


source







All Articles