【问题标题】:Newtonsoft.Json DeserializeObject passing null for guid 00000000-0000-0000-0000-000000000000Newtonsoft.Json DeserializeObject 为 guid 00000000-0000-0000-0000-000000000000 传递 null
【发布时间】:2014-11-22 15:10:05
【问题描述】:

我有一个用来表示身份的类,它包含一个字符串值。

然后我有另一个用于表示事件的类,这包括一个标识对象和一个字符串名称。

我可以很好地从对象序列化为 JSON 字符串,我得到了字符串:

{"Id":{"Value":"2e4146c2-66c9-4637-8936-29ccfc5df638"},"Name":"Jon Doe"}

但是,当我从上面的 JSON 转到对象时,在 MyIdentity 构造函数中,字符串 identityValue 以 "00000000-0000-0000-0000-000000000000" 的形式传入。

我还尝试为 MyIdentity 提供两个构造函数,一个用于字符串,一个用于 Guid,但结果相同。这背后的想法是将数据存储为字符串,但请记住,如果需要,我们可以转换为 Guid(因为身份将由字符串或 Guid 形成)。

public class MyEntityId : MyIdentity
{
    public MyEntityId(Guid identityValue)
        : base(identityValue)
    {
    }
}

public abstract class MyIdentity
{
    protected readonly bool convertableAsGuid;
    protected readonly string value;

    public string Value { get { return this.value; } }

    public MyIdentity(string identityValue)
    {
        this.value = identityValue;

        Guid guid;
        if(Guid.TryParse(identityValue, out guid)==false)
            this.convertableAsGuid = false;
    }

    public MyIdentity(Guid identityValue)
    {
        this.value = identityValue.ToString();
        this.convertableAsGuid = true;
    }
}

static void Main(string[] args)
{
    var evnt = new MyEvent(new MyEntityId(Guid.NewGuid()), "Jon Doe");

    var eventHeaders = new Dictionary<string, object>
    {
        {"EventClrTypeName", evnt.GetType().AssemblyQualifiedName}
    };
    var serializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None };
    var metadata = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(eventHeaders, serializerSettings));
    var data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(evnt, serializerSettings));
    string dataAsString = Encoding.UTF8.GetString(data);

    var eventClrTypeName = JObject.Parse(Encoding.UTF8.GetString(metadata)).Property("EventClrTypeName").Value;
    var obj = JsonConvert.DeserializeObject(dataAsString, Type.GetType((string)eventClrTypeName));
    // stepping through the above, a zero initialised GUID string is passed in to MyIdentity constructor
}

正如@hvd 友好地评论的那样,它似乎是 Value 只有一个 get 属性,如果我添加一个 set 属性也可以工作(所以我相信构造函数字符串值实际上没有被使用)。我不想在标识上放置 setter 的原因是为了编程设计,它是一个标识,一旦创建就不应更改。

我可以在属性上使用公共获取和保护集,我尝试了关键字[JsonProperty] 并且它有效......但是我不想用这些属性装饰我的域对象 - 还有其他方法吗?

【问题讨论】:

  • 问题可能是Value 属性没有setter,无法映射到构造函数参数,但这并不能真正帮助您修复它。
  • 对于它的价值,在我的情况下,我使用受保护的属性设置器获得了每个 GUID 成为空 GUID 的行为。这就是我提出这个问题的方式。我最终不得不把我的财产变成一个完整的公共财产,从建筑的角度来看我也不喜欢它,但实际上,在我的特殊情况下还不错。

标签: c# json json.net json-deserialization


【解决方案1】:

如果我理解正确,您在反序列化时初始化 Guid 时遇到问题,并且您不想创建设置器或使用属性来成功反序列化。请注意,我通过删除接受Guid 参数的构造函数来更改您的MyIdentity 类,因为它不是必需的,更改了Guid 逻辑的解析,因为它永远不会正确初始化convertableAsGuid 属性并创建MyEvent上课,因为您没有将其发布在您的问题上。我还创建了在反序列化期间使用的 MyCustomConverter 类。以下是课程:

public class MyCustomConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof (MyEvent);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jObject = JObject.Load(reader);
        existingValue = new MyEvent(new MyEntityId(jObject["Id"]["Value"].ToString()), jObject["Name"].ToString());

        return existingValue;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

public class MyEvent
{
    public MyEntityId Id { get; set; }

    public string Name { get; set; }

    public MyEvent(MyEntityId id, string name)
    {
        Id = id;
        Name = name;
    }
}

public class MyEntityId : MyIdentity
{
    public MyEntityId(string identityValue)
        : base(identityValue)
    {
    }
}

public abstract class MyIdentity
{
    protected readonly bool convertableAsGuid;
    protected readonly string value;

    public string Value { get { return this.value; } }

    public MyIdentity(string identityValue)
    {
        this.value = identityValue;

        Guid guid;
        if (Guid.TryParse(identityValue, out guid))
            this.convertableAsGuid = true;
    }
}

这里是序列化和反序列化逻辑:

static void Main(string[] args)
{
    var evnt = new MyEvent(new MyEntityId(Guid.NewGuid().ToString()), "Jon Doe");

    var eventHeaders = new Dictionary<string, object>
        {
            {"EventClrTypeName", evnt.GetType().AssemblyQualifiedName}
        };
    var serializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None };
    var metadata = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(eventHeaders, serializerSettings));
    var data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(evnt, serializerSettings));
    string dataAsString = Encoding.UTF8.GetString(data);

    var eventClrTypeName = JObject.Parse(Encoding.UTF8.GetString(metadata)).Property("EventClrTypeName").Value;
    var obj = JsonConvert.DeserializeObject<MyEvent>(dataAsString, new JsonConverter[] {new MyCustomConverter()});
}

演示:https://dotnetfiddle.net/asRtEI

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-07
    • 2021-07-29
    相关资源
    最近更新 更多