Serilog序列化List<object>丢失值及JSON转义问题求助
ASP.NET 6 + Serilog 处理Angular ngx-logger日志的序列化问题
问题现状
在ASP.NET 6后端接收Angular通过ngx-logger发送的日志时,碰到两个核心问题:
- 直接用Serilog解构
LogDto对象时,List<object>类型的Additional属性值丢失,被解析成[[[[]],[[]]]]这类无效结构; - 用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
相关产品推荐
相关产品推荐

