序列化动态属性名称使用JSON.NET对象 [英] Serialize Dynamic Property Name for an Object using JSON.NET

查看:136
本文介绍了序列化动态属性名称使用JSON.NET对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用JSON.NET我连接到一个REST API对象的序列化。一个需要被序列化到JSON在我的对象的属性有一个动态属性名称。
如果包含在结构此属性的值是一个数值,那么JSON属性为TYPE_ID,但是,如果这个值是一个字符串值,然后将JSON属性名称是类型代码。我试图使用自定义的 JsonConverter 这一点,但我得到一个 JsonWriterException 这个消息时,我试图序列:

I'm using JSON.NET for serialization of my objects for connecting to a REST API. One of the properties in my object that needs to be serialized to JSON has a dynamic property name. If the value contained in the struct for this property is a numeric value, then the JSON property is "type_id", however if this value is a string value, then the JSON property name is "type_code". I attempted to use a custom JsonConverter for this, but I get a JsonWriterException with this message when I attempt to serialize:

令牌属性名国家财产会导致一个无效的JSON对象。路径'。

"Token PropertyName in state Property would result in an invalid JSON object. Path ''."

下面是我对象的一个​​子集,看到下面我并没有在我的对象指定一个属性名称,作为这样的:

Below is a subset of my object, as seen below I didn't specify a property name in my object for that as such:

[JsonProperty("title",Required=Required.Always,Order=1)]
public string Title { get; set; }

[JsonProperty("date",Order=3)]
[JsonConverter(typeof(IsoDateTimeConverter))]
public DateTime Date { get; set; }

[JsonProperty(Order=2)]
[JsonConverter(typeof(TypeIdentifierJsonConverter))]
public TypeIdentifier DocTypeIdentifier { get; set; }

在TypeIdentifier类我在我的WriteJson()下面的方法:

In the TypeIdentifier class I have the following in my WriteJson() method:

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    TypeIdentifier docTypeId;
    id= (TypeIdentifier) value;

    writer.WritePropertyName(id.ParameterName);
    writer.WriteValue(id.Value);           
}



不过,我假设它默认为对象的属性的名称,而不是我的自定义之一,使两件属性名称为JSON字符串中的单个值。 ?如何属性名动态设置为这个,因为JsonPropertyAttribute标记出现没有明确规定时,拉对象的属性名

However, I am assuming it's defaulting to the name of the object's property instead of my custom one, causing two property names for a single value within the JSON string. How can the property name be set dynamically for this, since the JsonPropertyAttribute tag appears to pull the object's property name when not specified explicitly?

注:此对象将永远不需要。从这个程序,反序列化

NOTE: This object will never need to be deserialized from this app.

编辑::该对象被打上了 [JSONObject的(MemberSerialization.OptIn) 属性

This object is tagged with the [JsonObject(MemberSerialization.OptIn)] attribute

推荐答案

A JsonConverter 不能设置在一个父对象的属性的名称。当转换器的 WriteJson 方法被调用,属性名已被写入JSON;笔者期待只值这一点。这就是为什么你得到一个错误。为了使这项工作,定制转换器将对父对象作出。然后,该转换器将负责编写了儿童的属性名称和值。

A JsonConverter cannot set the name of a property in a parent object. When the converter's WriteJson method is called, the property name has already been written to the JSON; the writer is expecting only a value that point. That is why you are getting an error. In order to make this work, the custom converter would have to be made for the parent object. That converter would then be responsible for writing the property names and values of its children.

跟进

有可能写的父对象的变换,使得施加给它的JSON属性仍然尊重,同时还实现你想要的结果。我将概述下面的方法。

It is possible to write a converter for the parent object such that the JSON attributes applied to it are still respected, while still achieving the result you want. I'll outline the approach below.

首先,设置一点点。既然你没有说你的类叫什么,我会承担这个例子中,它被称为文件。我们只需要进行一次实质性改变它,这是清除从 [JsonConverter] 属性 DocTypeIdentifier 属性。因此,我们有:

First, a little bit of setup. Since you did not say what your class was called, I'll assume for this example that it is called Document. We only need to make one substantive change to it, and that is to remove the [JsonConverter] attribute from the DocTypeIdentifier property. So we have:

[JsonObject(MemberSerialization.OptIn)]
class Document
{
    [JsonProperty("title", Required = Required.Always, Order = 1)]
    public string Title { get; set; }

    [JsonProperty("date", Order = 3)]
    [JsonConverter(typeof(IsoDateTimeConverter))]
    public DateTime Date { get; set; }

    [JsonProperty(Order = 2)]
    public TypeIdentifier DocTypeIdentifier { get; set; }

    public string OtherStuff { get; set; }
}

您还没有显示出对于该代码的 TypeIdentifier 类,所以我就认为它看起来像这样,例如缘故:

You also did not show the code for the TypeIdentifier class, so I'll just assume it looks like this, for sake of example:

class TypeIdentifier
{
    public string Value { get; set; }
    public string ParameterName { get; set; }
}



有了这样的方式,我们可以使转换器。该方法是相当简单:我们加载文件 JObject ,采取的事实,即它尊重属性应用,然后回去和修复 DocTypeIdentifier 的序列化,因为它需要特殊处理。一旦我们有了这一点,我们写出来的 JObject JsonWriter 。下面是代码:

With that out of the way, we can make the converter. The approach is fairly straightforward: we load the Document into a JObject, taking advantage of the fact that it respects the attributes applied, then go back and fix the serialization of the DocTypeIdentifier since it needs special handling. Once we have that, we write out the JObject to the JsonWriter. Here is the code:

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

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Document doc = (Document)value;

        // Create a JObject from the document, respecting existing JSON attribs
        JObject jo = JObject.FromObject(value);

        // At this point the DocTypeIdentifier is not serialized correctly.
        // Fix it by replacing the property with the correct name and value.
        JProperty prop = jo.Children<JProperty>()
                           .Where(p => p.Name == "DocTypeIdentifier")
                           .First();

        prop.AddAfterSelf(new JProperty(doc.DocTypeIdentifier.ParameterName, 
                                        doc.DocTypeIdentifier.Value));
        prop.Remove();

        // Write out the JSON
        jo.WriteTo(writer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

现在我们已经转换,但美中不足的是,我们不能简单地用 [JsonConverter] 属性装点文件类才能使用它。如果我们这样做,我们最终会得到一个递归循环作为转换器试图用自己当我们加载文档到 JObject 。所以,相反,我们需要创建转换器的实例,并通过设置,把它传递给串行器。转换器的 CanConvert 的方法,确保它得到的正确类使用。在 JObject.FromObject 方法使用一个不同的序列化实例内部,所以它不会看到 DocumentConverter ,因此没有得到。麻烦

Now we have the converter, but the catch is we cannot simply decorate the Document class with a [JsonConverter] attribute in order to use it. If we did, we would end up with a recursive loop as the converter tried to use itself when we loaded the document into the JObject. So instead, we need to create an instance of the converter and pass it to the serializer via settings. The converter's CanConvert method ensures it gets used on the correct class. The JObject.FromObject method uses a different serializer instance internally, so it does not see the DocumentConverter and thus does not get into trouble.

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new DocumentConverter());

string json = JsonConvert.SerializeObject(doc, settings);

下面是显示在行动转换器演示:

Here is a demo showing the converter in action:

class Program
{
    static void Main(string[] args)
    {
        Document doc = new Document
        {
            Title = "How to write a JSON converter",
            Date = DateTime.Today,
            DocTypeIdentifier = new TypeIdentifier
            {
                ParameterName = "type_id",
                Value = "26"
            },
            OtherStuff = "this should not appear in the JSON"
        };

        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.Converters.Add(new DocumentConverter());
        settings.Formatting = Formatting.Indented;

        string json = JsonConvert.SerializeObject(doc, settings);
        Console.WriteLine(json);
    }
}

下面是从上面的输出:

{
  "title": "How to write a JSON converter",
  "type_id": "26",
  "date": "2014-03-28T00:00:00-05:00"
}

这篇关于序列化动态属性名称使用JSON.NET对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆