Colm Bhandal
Colm Bhandal

Reputation: 3851

Using log4net With Visual Studio Debugger

I'm having trouble getting my log4net.config file to load when using Visual Studio in debug mode for an Excel VSTO Plugin. The config file is in the top level directory of my project. I have the property "Copy to Output Directory" set to "Copy Always". This ensures the file is copied to bin/Debug/log4net.config. I can verify this is the case when I build.

However, the file won't load when I run in Debug mode. I gave up on trying to get the file to load automatically and decided to do it by code, as per the OP's code at the bottom of this question.

However, I realised that I needed to use an absolute path to the config file, as relative paths weren't picking it up. On further investigation, I realised that the executing DLL wasn't actually the DLL in the debug/bin folder. It was in the following location:

C:\Users\cbhandal\AppData\Local\assembly\dl3\MO52QQWP.9ZL\K36XZHGN.1PB\230751e6\d09b7fb2_19f6d401

Also the current working directory, as found by System.IO.Directory.GetCurrentDirectory(); was set to "C:\\Users\\cbhandal\\Documents".

Hard-coding the path as an absolute path works as in the following code:

var log4netConfig = "C:\\" + path + "\\Log4net.config";
var log4netInfo = new FileInfo(log4netConfig);
log4net.Config.XmlConfigurator.ConfigureAndWatch(log4netInfo);

But that's not a solution I can deploy. I'm stuck here. Wondering if there's a way to either force Visual studio to copy the .config file to that appdata/temp location, or if there's a way to programatically reference the folder where the original DLL lay- the one that was built. Or if anyone had any other solution?

Upvotes: 0

Views: 918

Answers (1)

Barry
Barry

Reputation: 372

For me the easiest solution was to use this: https://stackoverflow.com/a/6963420/4754981

But there are several other solutions on that link for different approaches, each with their caveats.

So mine looks like this:

using System.Reflection;
using System.IO;
using System;
public static class Extensions {
    private static string GetDirectory(this Assembly a) {
        string codeBase = a.CodeBase;
        UriBuilder uri = new UriBuilder(codeBase);
        string path = Uri.UnescapeDataString(uri.Path);
        return Path.GetDirectoryName(path);
    }
    private static void AlterLogPath(this log4net.Repository.ILoggerRepository repo, string newPath, string directory="") {
        log4net.Repository.Hierarchy.Hierarchy h = (log4net.Repository.Hierarchy.Hierarchy) repo;
        foreach (log4net.Appender.IAppender a in h.Root.Appenders) {
            if (a is log4net.Appender.FileAppender) {
                var fa = (log4net.Appender.FileAppender)a;
                var fileName = Path.GetFileName(fa.File);

                fa.File = newPath + (String.IsNullOrEmpty(directory)?"":(directory + Path.DirectorySeparatorChar.ToString())); // edit: filename is attached after next line automatically.
                fa.ActivateOptions();
                break;
            }
        }
    }
}

and in the bootup (via [assembly: System.Web.PreApplicationStartMethod] or otherwise for asp), or main app..

static void Main() {
    var PATH = Assembly.GetExecutingAssembly().GetDirectory() + Path.DirectorySeparatorChar.ToString();
    log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(PATH + "log4net.config"));
    log4net.LogManager.GetRepository().AlterLogPath(PATH, "Logs");
}

Upvotes: 1

Related Questions