JSONCONVERTERS和对象属性



我正在尝试找到一个困扰我几天的问题的答案目前是Silverlight。

i在服务器端具有.NET类(content1),该类别具有匹配的JSON转换器和具有类型content1属性的消息类(Message1)。这一切似乎都可以正常工作,问题是该属性被更改为键入对象(当前代码为)

public class Message1
{
    public string Name { get; set; }
    public object Payload { get; set; }
}

现在我的自定义jsonconverter不再被称为。

我已经将转换器放置在jsonserializer.converters Collection中,我可以看到CanConvert方法正在转换器上,但该属性是作为转换System.Object的请求。

我已经启用了typenamehandling并将其设置为自动(所有/对象/阵列不是SignalR断开的选项),并且可以看到写入我的JSON

的$ type属性
{
  "Name": "Test Message 1",
  "Payload": {
    "$type": "Models.Content1, Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0d90b1aaa82178d3",
    "Propert1": "This is a string"
  }
}

随着跟踪的打开,我可以看到已解决的类型

已解决类型'Models.Content1,模型,版本= 1.0.0.0,culture =中性,publicKeyToken = 0D90B1AAA82178D3TO Models.Content1。路径'有效载荷。$ type'。

但是我的自定义转换器从未被调用。

所以我问题的关键是,使用$ type时,有没有办法将json.net委派给我的类级别自定义转换器?

或失败,如果我编写自定义转换器并为我的对象属性注册它

public class Message1
{
    public string Name { get; set; }
    [JsonConverter(typeof(YetAnotherConverter))]
    public object Payload { get; set; }
}

是否有一种方法可以通过$ type属性窥视对象的类型,我真的很想这样做

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var data = JObject.Load(reader);
        var type = data.Property("$type");
        if (type.Value.Value<string>().Contains("Content1"))
        {
            var obj = serializer.Deserialize<Content1>(reader);
            return obj;
        }
        if (type.Value.Value<string>().Contains("Content2"))
        {
            var obj = serializer.Deserialize<Content2>(reader);
            return obj;
        }
        return serializer.Deserialize(reader);
    }

它会为我的类型调用正确的jsonconverter,但实际上不起作用,因为jsonreader只是向前,所以我不能对此类型"窥视"。

我想我可以走JSON序列化的途径,更像

{
  "Name": "Test Message 1",
  "Payload": {
    "$type": "Models.Content1, Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0d90b1aaa82178d3",
    "data": {
      "Propert1": "This is a string"
    }
  }
}

然后,我可以与读者一起通过JSON前进,获取$类型(此时可能在此时使用其他名称,因为我在原始使用中完全处理),找到数据部分,然后将其传递给具有正确对象类型的串行器,因此可以在类级别属性中调用转换器。

,老实说,这感觉就像我要沿着兔子洞走下去,这是不对的!

谢谢

史蒂芬。

在这种情况下似乎未调用多态类型的转换器。

您可以做的是创建YetAnotherConverter;在ReadJson中,将对象加载到JToken中,解析"$type"属性,然后致电JToken.ToObject(type, serializer)将中间JToken验证为最终类型。这样可以确保其转换器被调用。因此:

public class PolymorphicConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(object);
    }
    public override bool CanWrite { get { return false; } }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var token = JToken.Load(reader);
        if (token.Type != JTokenType.Object)
            return token;
        var typeString = (string)token["$type"];
        if (typeString == null)
            return token;
        string typeName, assemblyName;
        SplitFullyQualifiedTypeName(typeString, out typeName, out assemblyName);
        var type = serializer.Binder.BindToType(assemblyName, typeName);
        if (type != null)
            return token.ToObject(type, serializer);
        return token;
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
    // Utilities taken from https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs
    // I couldn't find a way to access these directly.
    public static void SplitFullyQualifiedTypeName(string fullyQualifiedTypeName, out string typeName, out string assemblyName)
    {
        int? assemblyDelimiterIndex = GetAssemblyDelimiterIndex(fullyQualifiedTypeName);
        if (assemblyDelimiterIndex != null)
        {
            typeName = fullyQualifiedTypeName.Substring(0, assemblyDelimiterIndex.Value).Trim();
            assemblyName = fullyQualifiedTypeName.Substring(assemblyDelimiterIndex.Value + 1, fullyQualifiedTypeName.Length - assemblyDelimiterIndex.Value - 1).Trim();
        }
        else
        {
            typeName = fullyQualifiedTypeName;
            assemblyName = null;
        }
    }
    private static int? GetAssemblyDelimiterIndex(string fullyQualifiedTypeName)
    {
        int scope = 0;
        for (int i = 0; i < fullyQualifiedTypeName.Length; i++)
        {
            char current = fullyQualifiedTypeName[i];
            switch (current)
            {
                case '[':
                    scope++;
                    break;
                case ']':
                    scope--;
                    break;
                case ',':
                    if (scope == 0)
                        return i;
                    break;
            }
        }
        return null;
    }
}

,然后:

public class Message1
{
    public string Name { get; set; }
    [JsonConverter(typeof(PolymorphicConverter))]
    public object Payload { get; set; }
}

相关内容

  • 没有找到相关文章

最新更新