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

Serilog序列化List<object>丢失值及JSON转义问题求助

ASP.NET 6 + Serilog 处理Angular ngx-logger日志的序列化问题

问题现状

在ASP.NET 6后端接收Angular通过ngx-logger发送的日志时,碰到两个核心问题:

  1. 直接用Serilog解构LogDto对象时,List<object>类型的Additional属性值丢失,被解析成[[[[]],[[]]]]这类无效结构;
  2. 用Newtonsoft.Json的JsonConvert.SerializeObject序列化后传入Serilog,Serilog.Sinks.File和Serilog.Sinks.MSSqlServer会保留JSON转义符\,导致存储的日志无法直接用T-SQL查询,试了多种去转义方法都无效。

需要达成的目标:让日志在File和MSSqlServer Sink中存储无转义的有效JSON,同时完整保留Additional属性的所有值。


当前配置与代码

File Sink配置

"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact",

SQLServer Sink配置

"addStandardColumns": [ "LogEvent" ],

后端接口与实体类代码

[HttpPost("logs")]
public IActionResult SaveFrontendLog([FromBody] LogDto log)
{
    _logger.LogInformation("Serilog Destruct 1 {@Log}", log, log.Additional);
    _logger.LogInformation("JsonConvert Serialize 2 {@Log}", JsonConvert.SerializeObject(log));
    return Ok();
}

public class LogDto
{
    [JsonConverter(typeof(JsonStringEnumConverter))]
    public NgxLoggerLevel Level { get; set; }
    public string Message { get; set; }
    public List<object> Additional { get; set; } // 问题属性
    public DateTime Timestamp { get; set; }
    public string FileName { get; set; }
    public int LineNumber { get; set; }
    public int ColumnNumber { get; set; }
}

尝试过的无效去转义方法

var token = JToken.Parse(JsonConvert.SerializeObject(log));
var myCleanJsonObject = JObject.Parse(JsonConvert.SerializeObject(log));
string cleanJson = Regex.Unescape(JsonConvert.SerializeObject(log));
string jsonString = JsonConvert.SerializeObject(log).Replace("\\", string.Empty);

可行解决方案

1. 修复Additional属性解构丢失问题

Serilog默认解构器对List<object>的嵌套/复杂类型支持不佳,最简单的解决方式是把List<object>换成Newtonsoft.Json的JArray类型:

public class LogDto
{
    [JsonConverter(typeof(JsonStringEnumConverter))]
    public NgxLoggerLevel Level { get; set; }
    public string Message { get; set; }
    public JArray Additional { get; set; } // 替换为JArray
    public DateTime Timestamp { get; set; }
    public string FileName { get; set; }
    public int LineNumber { get; set; }
    public int ColumnNumber { get; set; }
}

修改后直接用Serilog的解构语法即可:

_logger.LogInformation("Frontend log {@Log}", log);

Serilog能正确识别JArray并完整序列化所有内容,无需额外处理。

2. 消除JSON转义符残留

如果必须先序列化再传入Serilog,不要直接传字符串,而是把序列化后的字符串解析为JObject再传给Serilog:

var logJsonObject = JObject.Parse(JsonConvert.SerializeObject(log));
_logger.LogInformation("Frontend log {@Log}", logJsonObject);

这样Serilog会把JObject当作对象解构,而非字符串,不会生成多余的转义符。

同时检查配置:

  • File Sink使用CompactJsonFormatter时,只要传入的是对象而非字符串,生成的日志就是无转义的有效JSON;
  • MSSqlServer Sink的LogEvent列存储的是完整日志事件JSON,只要事件中的属性是正确解构的对象,存储的内容就不会有转义问题。

3. 自定义日志事件(备选方案)

如果上述方法不适用,可以手动构建Serilog的LogEvent,确保所有属性被正确序列化:

var logProperties = new Dictionary<string, object>
{
    { "Level", log.Level },
    { "Message", log.Message },
    { "Additional", log.Additional },
    { "Timestamp", log.Timestamp },
    { "FileName", log.FileName },
    { "LineNumber", log.LineNumber },
    { "ColumnNumber", log.ColumnNumber }
};

_logger.Write(LogEventLevel.Information, new MessageTemplate("Frontend log", Enumerable.Empty<MessageTemplateToken>()), logProperties);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 06:11:15