【问题标题】:layout="${aspnet-request-posted-body}" in the NLog.config now causes an internal NLog exceptionNLog.config 中的 layout="${aspnet-request-posted-body}" 现在会导致内部 NLog 异常
【发布时间】:2022-07-25 19:43:08
【问题描述】:

NLog、NLog.Database、NLog.Extensions.Logging 和 NLog.Web.AspNetCore 的版本为 5.0.0。 平台为 .NET Core 3.1。

这曾经在 NLog 4.x 系列中可以正常工作,但现在这会导致异常,我还没有找到解决方法。我对 NLog.config 文件所做的唯一更改是添加对 NLog.Database 程序集的引用。当我删除 NLog.config 中 layout="${aspnet-request-posted-body}" 的行时,它工作正常。

NLog.config 内容

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
      autoReload="true"
      throwExceptions="false"
      throwConfigExceptions="true"
      internalLogLevel="Warn" internalLogFile="c:\temp\nlog-internal.log">
    <!-- enable asp.net core layout renderers -->
  <extensions>
      <add assembly="NLog.Database"/>
      <add assembly="NLog.Web.AspNetCore"/>
  </extensions>
  <targets async="true">
    <target name="database" xsi:type="Database">
      <dbProvider>Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient</dbProvider>
      <connectionString>Server=xxxxxx;Database=xxxxxx;Trusted_Connection=True;Encrypt=True;</connectionString>
      <commandText>
          INSERT INTO CisServiceLog
          (
          [Date],
          [Thread],
          [Level],
          [Logger],
          [Message],
          [Exception],
          [ApplicationDomain],
          [MachineName],
          [Action],
          [Controller],
          [Url],
          [Method],
          [RemoteIp],
          [IISSiteName],
          [ContentType],
          [Host],
          [QueryString],
          [Request],
          [ASPNetTraceID],
          [UserAgent]
          )
          VALUES
          (
          @log_date,
          @thread,
          @log_level,
          @logger,
          @message,
          @exception,
          @appdomain,
          @machine_name,
          @action,
          @controller,
          @url,
          @method,
          @ip,
          @iissitename,
          @contenttype,
          @host,
          @querystring,
          @request,
          @aspnettraceid,
          @useragent
          )
      </commandText>
      <parameter name="@log_date"  layout="${date}" />
      <parameter name="@thread"    layout="${threadid}" size="10" />
      <parameter name="@log_level" layout="${level}"    size="8" />
      <parameter name="@logger"    layout="${logger}"   size="256" />
      <parameter name="@message"   layout="${message}"  size="8000" />
      <parameter name="@exception" layout="${exception:tostring}"  size="8000" />
      <parameter name="@appdomain" layout="${appdomain}"           size="256" />
      <parameter name="@machine_name" layout="${machinename}"      size="256" />
        <parameter name="@action"       layout="${aspnet-mvc-action}"       size="256" />
        <parameter name="@controller"   layout="${aspnet-mvc-controller}"   size="256" />
        <parameter name="@url"          layout="${aspnet-request-url}"      size="1024" />
        <parameter name="@method"       layout="${aspnet-request-method}"   size="16" />
        <parameter name="@ip"           layout="${aspnet-request-ip:CheckForwardedForHeader=true}" size="32" />
        <parameter name="@iissitename"  layout="${iis-site-name}"           size="256" />
        <parameter name="@contenttype"  layout="${aspnet-request-contenttype}"   size="256" />
        <parameter name="@host"         layout="${aspnet-request-host}"          size="256" />
        <parameter name="@querystring"  layout="${aspnet-request-querystring}"   size="4096" />
        <parameter name="@request"      layout="${aspnet-request-posted-body}"   size="8000" />
        <parameter name="@aspnettraceid" layout="${aspnet-traceidentifier}"      size="64" />
        <parameter name="@useragent"    layout="${aspnet-request-useragent}"     size="1024" />
    </target>
  </targets>
  <rules>
    <logger name="*" minlevel="Warn" writeTo="database" />
  </rules>
</nlog>

异常堆栈跟踪:

NLog.NLogConfigurationException: Exception when loading configuration C:\git\Commercial_BOLCISServices\BusinessOnline.WebApi\bin\Debug\netcoreapp3.1\Logging.config
 ---> NLog.NLogConfigurationException: 'DatabaseParameterInfo' cannot assign property 'Layout'='${aspnet-request-posted-body}'. Error: Error parsing layout aspnet-request-posted-body
 ---> NLog.NLogConfigurationException: Error parsing layout aspnet-request-posted-body
 ---> System.ArgumentException: LayoutRenderer symbol-name is unknown: 'aspnetrequestpostedbody'. Extension NLog.Web.AspNetCore not included?
   at NLog.Config.Factory`2.CreateInstance(String itemName)
   at NLog.Layouts.LayoutParser.GetLayoutRenderer(String typeName, ConfigurationItemFactory configurationItemFactory, Nullable`1 throwConfigExceptions)
   --- End of inner exception stack trace ---
   at NLog.Layouts.LayoutParser.GetLayoutRenderer(String typeName, ConfigurationItemFactory configurationItemFactory, Nullable`1 throwConfigExceptions)
   at NLog.Layouts.LayoutParser.ParseLayoutRenderer(ConfigurationItemFactory configurationItemFactory, SimpleStringReader stringReader, Nullable`1 throwConfigExceptions)
   at NLog.Layouts.LayoutParser.CompileLayout(ConfigurationItemFactory configurationItemFactory, SimpleStringReader sr, Nullable`1 throwConfigExceptions, Boolean isNested, String& text)
   at NLog.Layouts.LayoutParser.CompileLayout(String value, ConfigurationItemFactory configurationItemFactory, Nullable`1 throwConfigExceptions, String& text)
   at NLog.Layouts.SimpleLayout.SetLayoutText(String value, Nullable`1 throwConfigExceptions)
   at NLog.Layouts.SimpleLayout..ctor(String txt, ConfigurationItemFactory configurationItemFactory, Nullable`1 throwConfigExceptions)
   at NLog.Layouts.SimpleLayout..ctor(String txt, ConfigurationItemFactory configurationItemFactory)
   at NLog.Internal.PropertyHelper.TryParseLayoutValue(String stringValue, ConfigurationItemFactory configurationItemFactory)
   at NLog.Internal.PropertyHelper.TryNLogSpecificConversion(Type propertyType, String value, ConfigurationItemFactory configurationItemFactory, Object& newValue)
   at NLog.Internal.PropertyHelper.SetPropertyFromString(Object targetObject, PropertyInfo propInfo, String stringValue, ConfigurationItemFactory configurationItemFactory)
   --- End of inner exception stack trace ---
   at NLog.Internal.PropertyHelper.SetPropertyFromString(Object targetObject, PropertyInfo propInfo, String stringValue, ConfigurationItemFactory configurationItemFactory)
   at NLog.Internal.PropertyHelper.SetPropertyFromString(Object targetObject, String propertyName, String stringValue, ConfigurationItemFactory configurationItemFactory)
   at NLog.Config.LoggingConfigurationParser.SetPropertyValueFromString(Object targetObject, String propertyName, String propertyValue, ValidatedConfigurationElement element)
   at NLog.Config.LoggingConfigurationParser.ConfigureObjectFromAttributes(Object targetObject, ValidatedConfigurationElement element, Boolean ignoreType)
   at NLog.Config.LoggingConfigurationParser.ConfigureFromAttributesAndElements(Object targetObject, ValidatedConfigurationElement element, Boolean ignoreTypeProperty)
   at NLog.Config.LoggingConfigurationParser.ParseArrayItemFromElement(Type elementType, ValidatedConfigurationElement element)
   at NLog.Config.LoggingConfigurationParser.AddArrayItemFromElement(Object o, PropertyInfo propInfo, ValidatedConfigurationElement element)
   at NLog.Config.LoggingConfigurationParser.SetPropertyValuesFromElement(Object o, ValidatedConfigurationElement childElement, ILoggingConfigurationElement parentElement)
   at NLog.Config.LoggingConfigurationParser.ParseTargetElement(Target target, ValidatedConfigurationElement targetElement, Dictionary`2 typeNameToDefaultTargetParameters)
   at NLog.Config.LoggingConfigurationParser.ParseTargetsElement(ValidatedConfigurationElement targetsElement)
   at NLog.Config.LoggingConfigurationParser.ParseNLogSection(ILoggingConfigurationElement configSection)
   at NLog.Config.XmlLoggingConfiguration.ParseNLogSection(ILoggingConfigurationElement configSection)
   at NLog.Config.LoggingConfigurationParser.LoadConfig(ILoggingConfigurationElement nlogConfig, String basePath)
   at NLog.Config.XmlLoggingConfiguration.ParseNLogElement(ILoggingConfigurationElement nlogElement, String filePath, Boolean autoReloadDefault)
   at NLog.Config.XmlLoggingConfiguration.ParseTopLevel(NLogXmlElement content, String filePath, Boolean autoReloadDefault)
   at NLog.Config.XmlLoggingConfiguration.Initialize(XmlReader reader, String fileName, Boolean ignoreErrors)

【问题讨论】:

    标签: nlog


    【解决方案1】:

    NLog.Web.AspNetCore 版本。 5.0 删除了 ${aspnet-request-posted-body},因为它的实现不是线程安全的,并且引入了不可预测的行为。

    https://github.com/NLog/NLog/wiki/AspNet-Request-posted-body-layout-renderer

    认为正确的解决方案是使用中间件来捕获/缓冲发布的正文,然后注入到像 HttpContext.Items (${aspnet-item}) 或 NLog ScopeContext (${scopeproperty}) 这样的安全位置

    欢迎Pull-Requests提供此类中间件的原型。

    【讨论】:

    • 谢谢!我会阅读上面的链接并考虑中间件,我已经在我的应用程序中使用了中间件功能来进行其他日志记录。
    • 我已经提交了一个拉取请求。
    • 感谢您的拉取请求:github.com/NLog/NLog.Web/pull/781 NLog.Web v5.0.1 应该让${aspnet-request-posted-body} 再次工作。
    【解决方案2】:

    感谢@bakgerman 现在 NLog.Web.AspNetCore v5.1 在中间件的帮助下重新引入了${aspnet-request-posted-body}

    app.UseMiddleware<NLog.Web.NLogRequestPostedBodyMiddleware>();
    

    不再需要显式调用context.Request.EnableBuffering();,因为它由中间件处理。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-13
      • 1970-01-01
      相关资源
      最近更新 更多