使用JSON.NET序列化对象的动态属性名



我使用JSON。. NET用于序列化我的对象以连接到REST API。我的对象中需要序列化为JSON的属性之一具有动态属性名称。如果这个属性的结构中包含的值是一个数值,那么JSON属性是"type_id",但是如果这个值是一个字符串值,那么JSON属性名称是"type_code"。我试图为此使用自定义JsonConverter,但是当我尝试序列化时,我得到了带有此消息的JsonWriterException:

"状态属性中的令牌PropertyName将导致无效的JSON对象。路径"。"

下面是我的对象的一个子集,如下所示,我没有在我的对象中为它指定一个属性名:

[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()方法中有以下内容:

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标签在未显式指定时似乎会拉出对象的属性名称?

注意:这个对象永远不需要从这个应用程序中反序列化。

EDIT:这个对象被标记为[JsonObject(MemberSerialization.OptIn)]属性

JsonConverter不能设置父对象中的属性名称。当转换器的WriteJson方法被调用时,属性名已经被写入JSON;写作者期望的只是那个点的值。这就是为什么你会得到一个错误。为了使此工作,必须为父对象创建自定义转换器。然后,该转换器将负责编写其子属性的名称和值。

后续

可以为父对象编写一个转换器,这样应用于它的JSON属性仍然受到尊重,同时仍然实现您想要的结果。我将在下面概述这种方法。

首先,做一点设置。由于您没有说明您的类被称为什么,因此在本例中,我假设它被称为Document。我们只需要对它做一个实质性的改变,那就是从DocTypeIdentifier属性中删除[JsonConverter]属性。我们输入:

[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类的代码,因此为了便于示例,我将假设它看起来像这样:

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

有了这个,我们就可以制作转换器了。该方法相当简单:我们将Document加载到JObject中,利用它尊重所应用的属性这一事实,然后返回并修复DocTypeIdentifier的序列化,因为它需要特殊处理。一旦我们得到了这个,我们将JObject写入JsonWriter。下面是代码:

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]属性修饰Document类以便使用它。如果这样做,当我们将文档加载到JObject中时,转换器会试图使用它自己,从而导致递归循环。因此,我们需要创建转换器的实例,并通过设置将其传递给序列化器。转换器的CanConvert方法确保在正确的类上使用它。JObject.FromObject方法在内部使用不同的序列化器实例,因此它看不到DocumentConverter,因此不会遇到麻烦。

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new DocumentConverter());
string json = JsonConvert.SerializeObject(doc, settings);

下面是演示转换器的示例:

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"
}

相关内容

  • 没有找到相关文章

最新更新