【问题标题】:Using Newtonsoft (Json.NET) to serialize System.Diagnostics.EventLogEntry collection使用 Newtonsoft (Json.NET) 序列化 System.Diagnostics.EventLogEntry 集合
【发布时间】:2015-11-15 16:46:41
【问题描述】:

我正在尝试收集满足特定查询的 Windows 事件并将它们序列化为 JSON,以便我可以将该集合导入 MongoDB 数据库。这只是我在练习和胡闹,但我被困在这一点上,希望能够继续前进。

问题:

当我使用JsonConvert.SerializeObject(...) 时,我肯定会用它来序列化与对象类似的东西,因为有一些属性仍然存在:

public class EventSerializer
{
    public static void Serialize(EventLogEntry eventLogEntry)
    {
        var traceWriter = new MemoryTraceWriter();
        JsonConvert.SerializeObject(eventLogEntry, Formatting.Indented, new JsonSerializerSettings
        {
            TraceWriter = traceWriter
        });
        Console.WriteLine(traceWriter);
    }
}

输出:

{
    "DataBuffer": "<seemingly-random, long string>",
    "LogName": "Application",
    "MachineName": "<my machine's name>"
}

我什至可以反序列化对象并得到我期望的结果。但我真的不希望其中的 DataBuffer 键值对,我希望 EventLogEntry 的内容可读,以便我可以从 MongoDB 中解析该信息。

我一直在查看 Json.NET 的文档,我想知道是否需要创建自己的 Converter 或其他东西,但我在从这里理解这一切时遇到了一些麻烦.还有人谈论in the documentation,关于选择加入/退出序列化特定属性/字段的能力,但我不清楚如何对声明/规范不是的对象执行此操作自己写的。

感谢任何和所有帮助/建议。

【问题讨论】:

    标签: c# json mongodb serialization json.net


    【解决方案1】:

    据我所知,您无法将 JSON 反序列化为新的 EventLogEntry 对象。一个原因是EventLogEntry中的一些属性是只读属性,这些属性的getter包含计算值的逻辑,即它们不是从内部存储的字段中获取值的简单getter。

    我建议您创建一个特殊的对象来保存数据。这是一个例子:

    public class MyEventLogEntry
    {
        public string MachineName { get; set; }
        public DateTime GeneratedTime { get; set; }
        public string Message { get; set; }
        public long InstanceId { get; set; } 
    }
    

    您可以将您感兴趣的事件属性放入此类中。它们甚至可以与EventLogEntry 中的名称不同。

    您可以使用AutoMapper 轻松地将EventLogEntry 转换为MyEventLogEntry。或者,您可以根据需要手动操作。

    这是一个使用 AutoMapper 的代码示例:

    AutoMapper.Mapper.CreateMap<EventLogEntry, MyEventLogEntry>()
        .ForMember(dst => dst.InstanceId, opt => opt.MapFrom(src => src.InstanceId))
        .ForMember(dst => dst.Message, opt => opt.MapFrom(src => src.Message))
        .ForMember(dst => dst.GeneratedTime, opt => opt.MapFrom(src => src.TimeGenerated))
        .ForMember(dst => dst.MachineName, opt => opt.MapFrom(src => src.MachineName));
    
    EventLog log = new EventLog("Application");
    
    EventLogEntry entry = log.Entries[0];
    
    MyEventLogEntry my_entry = AutoMapper.Mapper.Map<EventLogEntry, MyEventLogEntry>(entry);
    
    string json = JsonConvert.SerializeObject(my_entry);
    
    MyEventLogEntry deserialized_entry = JsonConvert.DeserializeObject<MyEventLogEntry>(json);
    

    请注意,对AutoMapper.Mapper.CreateMap 的调用只需执行一次(例如,在您的应用程序开始时)。

    当你想读/写数据库时,你可以使用MyEventLogEntry

    【讨论】:

    • 非常感谢您的帮助!如果愿意,您能否详细说明为什么只读属性会阻止这样的序列化发生?或者是吸气剂正在计算而不是仅仅返回一个私人成员?我真的很想更好地理解这一点。此外,AutoMapper 使用起来非常简洁。再次感谢。
    • 反序列化器反序列化对象的最简单方法是调用属性设置器,而只读属性没有属性设置器。关于私有字段,如果只读属性有一个支持字段,理论上您可以使用Reflection 做一些魔术并更改此类私有字段的值。
    猜你喜欢
    • 2016-09-10
    • 2021-11-10
    • 2015-02-16
    • 2019-01-29
    • 1970-01-01
    • 2018-11-09
    • 1970-01-01
    相关资源
    最近更新 更多