在Visual Studio中使用NLog设置多个项目的C#解决方案

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

  • DLL
  • WPF应用程序(需要DLL的方法)

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

这是我不明白的:

  1. 我似乎没有必要在每个项目中包含相同的NLog DLL。
  2. 但是,DLL应该可以在其他解决方案中重用,也就是说, NLog DLL必须以某种方式包含在DLL项目中。

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

你需要在你使用它的所有项目中使用DLL,当然你需要使用可执行文件的二进制文件(在你的情况下是WPF应用程序)部署它,以便可以在运行时找到它并使用它。

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

希望这可以帮助 ;-)

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

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

 using System; using System.Runtime.CompilerServices; using NLog; namespace ProjectName.Core.Utilities { ///  /// Generic NLog wrapper. ///  public static class Logger { ///  /// Gets or sets the enabled status of the logger. ///  public static bool Enabled { get { return LogManager.IsLoggingEnabled(); } set { if (value) { while (!Enabled) LogManager.EnableLogging(); } else { while (Enabled) LogManager.DisableLogging(); } } } ///  /// Writes the diagnostic message at the Trace level. ///  ///  ///  ///  ///  ///  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); } ///  /// Writes the diagnostic message at the Debug level. ///  ///  ///  ///  ///  ///  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); } ///  /// Writes the diagnostic message at the Info level. ///  ///  ///  ///  ///  ///  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); } ///  /// Writes the diagnostic message at the Warn level. ///  ///  ///  ///  ///  ///  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); } ///  /// Writes the diagnostic message at the Error level. ///  ///  ///  ///  ///  ///  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); } ///  /// Writes the diagnostic message at the Fatal level. ///  ///  ///  ///  ///  ///  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); } ///  /// Writes the specified diagnostic message. ///  ///  ///  ///  ///  ///  ///  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}) 

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