12

我在 Visual Studio 2012 中的解决方案目前包含两个项目:

  • 动态链接库
  • WPF 应用程序(需要 DLL 的方法)

DLL 和 WPF 应用程序都NLog用于日志记录。目前,每个项目都包含NLogDLL 本身。

这是我不明白的:

  1. 我似乎没有必要NLog在每个项目中包含相同的 DLL。
  2. 然而,DLL 应该可以在其他解决方案中重复使用,即,NLogDLL 必须以某种方式包含在 DLL 项目中。

设置 Visual Studio 解决方案和/或项目的适当方法是什么?

4

3 回答 3

9

好吧,您在使用它的所有项目中都需要该 DLL,并且您肯定需要将它与可执行文件的二进制文件(在您的情况下为 WPF 应用程序)一起部署,以便可以在运行时找到和使用它。

我在所有项目中倾向于做的是围绕日志引擎创建一个包装器,这样我就不需要引用和依赖特定的第三方日志 API,如 Log4Net 或 NLog,所以我在任何地方都使用我的包装器日志记录类,然后我仅在包装类的项目和可执行项目中引用日志记录程序集,以将程序集部署到 bin 文件夹。

希望这可以帮助 ;-)

于 2013-03-12T08:45:21.293 回答
8

如果您的 DLL 只是您计划在各个项目之间共享的核心库,则将 NLog 引用和包装器代码添加到该库可能是明智之举,然后确保任何消费者应用程序(例如您的 WPF 项目)具有 NLog .config 文件与之关联。

由于您使用的是 VS2012,我假设您也很可能使用 .NET 4.5,它允许您利用新的调用者信息属性。我为基本的 NLog 包装器编写了以下代码,并相信它在效率(不使用 StackTrace)和可用性之间取得了完美的平衡。

using System;
using System.Runtime.CompilerServices;
using NLog;

namespace ProjectName.Core.Utilities
{
    /// <summary>
    /// Generic NLog wrapper.
    /// </summary>
    public static class Logger
    {
        /// <summary>
        /// Gets or sets the enabled status of the logger.
        /// </summary>
        public static bool Enabled
        {
            get { return LogManager.IsLoggingEnabled(); }
            set
            {
                if (value)
                {                    
                    while (!Enabled) LogManager.EnableLogging();
                }
                else
                {
                    while (Enabled) LogManager.DisableLogging();
                }
            }
        }

        /// <summary>
        /// Writes the diagnostic message at the Trace level.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="exception"></param>
        /// <param name="callerPath"></param>
        /// <param name="callerMember"></param>
        /// <param name="callerLine"></param>
        public static void Trace(string message, Exception exception = null,
            [CallerFilePath] string callerPath = "",
            [CallerMemberName] string callerMember = "",
            [CallerLineNumber] int callerLine = 0)
        {
            Log(LogLevel.Trace, message, exception, callerPath, callerMember, callerLine);
        }

        /// <summary>
        /// Writes the diagnostic message at the Debug level.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="exception"></param>
        /// <param name="callerPath"></param>
        /// <param name="callerMember"></param>
        /// <param name="callerLine"></param>
        public static void Debug(string message, Exception exception = null,
            [CallerFilePathAttribute] string callerPath = "",
            [CallerMemberName] string callerMember = "",
            [CallerLineNumber] int callerLine = 0)
        {
            Log(LogLevel.Debug, message, exception, callerPath, callerMember, callerLine);
        }

        /// <summary>
        /// Writes the diagnostic message at the Info level.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="exception"></param>
        /// <param name="callerPath"></param>
        /// <param name="callerMember"></param>
        /// <param name="callerLine"></param>
        public static void Info(string message, Exception exception = null,
            [CallerFilePathAttribute] string callerPath = "",
            [CallerMemberName] string callerMember = "",
            [CallerLineNumber] int callerLine = 0)
        {
            Log(LogLevel.Info, message, exception, callerPath, callerMember, callerLine);
        }

        /// <summary>
        /// Writes the diagnostic message at the Warn level.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="exception"></param>
        /// <param name="callerPath"></param>
        /// <param name="callerMember"></param>
        /// <param name="callerLine"></param>
        public static void Warn(string message, Exception exception = null,
            [CallerFilePathAttribute] string callerPath = "",
            [CallerMemberName] string callerMember = "",
            [CallerLineNumber] int callerLine = 0)
        {
            Log(LogLevel.Warn, message, exception, callerPath, callerMember, callerLine);
        }

        /// <summary>
        /// Writes the diagnostic message at the Error level.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="exception"></param>
        /// <param name="callerPath"></param>
        /// <param name="callerMember"></param>
        /// <param name="callerLine"></param>
        public static void Error(string message, Exception exception = null,
            [CallerFilePathAttribute] string callerPath = "",
            [CallerMemberName] string callerMember = "",
            [CallerLineNumber] int callerLine = 0)
        {
            Log(LogLevel.Error, message, exception, callerPath, callerMember, callerLine);
        }

        /// <summary>
        /// Writes the diagnostic message at the Fatal level.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="exception"></param>
        /// <param name="callerPath"></param>
        /// <param name="callerMember"></param>
        /// <param name="callerLine"></param>
        public static void Fatal(string message, Exception exception = null,
            [CallerFilePathAttribute] string callerPath = "",
            [CallerMemberName] string callerMember = "",
            [CallerLineNumber] int callerLine = 0)
        {            
            Log(LogLevel.Fatal, message, exception, callerPath, callerMember, callerLine);
        }

        /// <summary>
        /// Writes the specified diagnostic message.
        /// </summary>
        /// <param name="level"></param>
        /// <param name="message"></param>
        /// <param name="exception"></param>
        /// <param name="callerPath"></param>
        /// <param name="callerMember"></param>
        /// <param name="callerLine"></param>
        private static void Log(LogLevel level, string message, Exception exception = null, string callerPath = "", string callerMember = "", int callerLine = 0)
        {
            // get the source-file-specific logger
            var logger = LogManager.GetLogger(callerPath);

            // quit processing any further if not enabled for the requested logging level
            if (!logger.IsEnabled(level)) return;

            // log the event with caller information bound to it
            var logEvent = new LogEventInfo(level, callerPath, message) {Exception = exception};
            logEvent.Properties.Add("callerpath", callerPath);
            logEvent.Properties.Add("callermember", callerMember);
            logEvent.Properties.Add("callerline", callerLine);
            logger.Log(logEvent);
        }
    }
}

然后尝试将其放入 NLog.config 中目标之一的布局字段中,以获取详细的调用者信息。

${event-context:item=callerpath}:${event-context:item=callermember}(${event-context:item=callerline})
于 2013-03-16T06:04:08.573 回答
1

你最好抽象出你的日志机制的使用。我在这篇博文中对此进行了描述,它是关于 log4net 的,但无论您使用什么框架,它的原理都是一样的。在任何情况下,您在使用它的每个项目中都需要日志程序集,但是通过抽象它很容易用其他东西替换它(例如在测试时)。日志记录是基础设施,因此您可以将接口和具体实现放在基础设施项目中,并从您要记录的项目中引用该接口和具体实现。

于 2013-03-12T09:06:12.940 回答