You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core 3.1中Windsor Castle集成NLog实现自定义日志写入数据库的问题求助

解决Windsor Castle集成NLog时自定义日志属性写入数据库的问题

看起来你遇到的核心问题是没有正确将自定义日志属性传递给NLog的event-properties,而是错误地用InfoFormat把参数嵌入到日志字符串里,导致数据库target无法获取到正确的属性值,进而引发类型转换和空值异常。下面一步步帮你解决:

1. 理解问题根源

你用_logger.InfoFormat(...)的方式,只是把参数拼接成了日志消息文本,并没有把这些值设置为NLog的event-properties。而你的NLog数据库配置里,是通过${event-properties:item=XXX}来读取属性值的——这意味着这些值根本没被传递到数据库target,所以参数要么是空字符串,要么是错误的类型,最终触发SQL异常。

2. 正确传递自定义日志属性

你需要用NLog的结构化日志或者**WithProperty方法**来传递自定义属性,而不是拼字符串。这里有两种常用方式:

方式一:使用匿名对象传递结构化数据

// 定义你的自定义日志数据
var customLog = new
{
    CreateDate = DateTime.Now,
    UserProfileId = Guid.NewGuid(), // 确保这里是有效的Guid,匹配数据库列类型
    IsError = false,
    Type = 1,
    Username = "当前登录用户",
    Message = "abcd",
    Description = "这是一条自定义业务日志",
    StackTrace = string.Empty,
    AddressIP = "192.168.1.100"
};

// 用结构化日志方式传递,NLog会自动解析对象属性到event-properties
_logger.Info("业务日志记录: {LogData}", customLog);

方式二:逐个添加属性(更灵活)

如果需要单独控制每个属性,可以用WithProperty链式调用:

_logger.WithProperty("CreateDate", DateTime.Now)
       .WithProperty("UserProfileId", Guid.NewGuid())
       .WithProperty("IsError", false)
       .WithProperty("Type", 1)
       .WithProperty("Username", "当前登录用户")
       .WithProperty("Message", "abcd")
       .WithProperty("Description", "这是一条自定义业务日志")
       .WithProperty("StackTrace", string.Empty)
       .WithProperty("AddressIP", "192.168.1.100")
       .Info("业务日志记录");

注意:如果用Windsor Castle的抽象Logger

如果你的_logger是Windsor Castle提供的ILogger抽象,可能需要先获取底层的NLog Logger实例才能使用WithProperty:

// 转换为底层NLog Logger
var nlogLogger = (NLog.Logger)_logger.Logger;
nlogLogger.WithProperty("CreateDate", DateTime.Now)
          // 其他属性...
          .Info("业务日志记录");

3. 修正NLog配置(确保参数匹配)

检查你的nlog.config,确保:

  • 数据库连接字符串connectionString是有效的(替换成你的实际连接字符串)
  • 所有参数名和event-properties的key完全一致(比如@UserProfileId对应UserProfileId属性)
  • 不需要额外的CASE转换,只要传递的属性类型和数据库列类型匹配(比如Guid对应uniqueidentifier,bool对应bit等)

修正后的核心配置部分(和你原来的一致,只要确保属性传递正确即可):

<target name="database" xsi:type="Database" connectionString="你的数据库连接字符串" 
        commandText="INSERT INTO [dbo].[EventLog] ( [CreateDate], [UserProfileId], [IsError], [Type], [Username], [Message], [Description], [StackTrace], [AddressIP] ) 
                      VALUES ( @CreateDate, @UserProfileId, @IsError, @Type, @Username, @Message, @Description, @StackTrace, @AddressIP )">
    <parameter name="@CreateDate" layout="${event-properties:item=CreateDate}" />
    <parameter name="@UserProfileId" layout="${event-properties:item=UserProfileId}" />
    <parameter name="@IsError" layout="${event-properties:item=IsError}" />
    <parameter name="@Type" layout="${event-properties:item=Type}" />
    <parameter name="@Username" layout="${event-properties:item=Username}" />
    <parameter name="@Message" layout="${event-properties:item=Message}" />
    <parameter name="@Description" layout="${event-properties:item=Description}" />
    <parameter name="@StackTrace" layout="${event-properties:item=StackTrace}" />
    <parameter name="@AddressIP" layout="${event-properties:item=AddressIP}" />
</target>

4. 调试验证

可以添加一个控制台target来查看event-properties是否正确传递,方便排查问题:

<targets>
    <!-- 你的文件和数据库target -->
    <target name="console" xsi:type="Console" layout="${longdate}|${level}|${message}|${all-event-properties}" />
</targets>
<rules>
    <logger name="*" minlevel="Trace" writeTo="console" />
    <!-- 你的其他规则 -->
</rules>

运行程序后,控制台会输出所有传递的属性,你可以确认每个属性是否存在、值是否正确。

为什么之前的方法失败?

  • InfoFormat只是生成格式化的日志消息,并没有把参数绑定到event-properties,所以数据库target读取到的都是空值或错误的字符串。
  • 你添加的CASE语句试图处理空字符串,但因为属性根本没被传递,所以转换后得到NULL,而数据库的UserProfileId(或Id)列不允许空值,因此触发新的异常。

内容的提问来源于stack exchange,提问作者axern

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 05:32:40