我正在使用JSON.NET对对象进行序列化以连接到REST API。我对象中需要序列化为JSON的属性之一具有动态属性名称。如果此属性的struct中包含的值是数字值,则JSON属性为“ type_id”,但是,如果此值是字符串值,则JSON属性名称为“ type_code”。我尝试为此使用自定义JsonConverter,但是JsonWriterException在尝试序列化时收到以下消息:
JsonConverter
JsonWriterException
“状态为Property的令牌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标记似乎会拉动对象的属性名称,因此如何动态设置属性名称呢?
注意:此对象将永远不需要从此应用程序反序列化。
编辑: 此对象标记有[JsonObject(MemberSerialization.OptIn)]属性
[JsonObject(MemberSerialization.OptIn)]
一个JsonConverter不能设置在一个父对象的属性的名称。WriteJson调用转换器的方法时,属性名称已被写入JSON;作者只期望有一个价值。这就是为什么您会得到一个错误。为了使这项工作,必须为父对象创建自定义转换器。然后,该转换器将负责编写其子代的属性名称和值。
WriteJson
跟进
可以为父对象编写一个转换器,以便仍尊重应用到它的JSON属性,同时仍然获得所需的结果。我将在下面概述该方法。
首先,进行一些设置。由于您没有说出您的班级叫什么,因此在此示例中,我假设它被称为Document。我们只需要对其进行实质性更改,那就是[JsonConverter]从DocTypeIdentifier属性中删除该属性。因此,我们有:
Document
[JsonConverter]
DocTypeIdentifier
[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该类的代码,因此,出于示例的考虑,我假设它看起来像这样:
TypeIdentifier
class TypeIdentifier { public string Value { get; set; } public string ParameterName { get; set; } }
有了这些,我们就可以制造转换器。该方法非常简单:我们利用尊重应用的属性这一事实将其加载Document到中JObject,然后返回并修复的序列化,DocTypeIdentifier因为它需要特殊处理。一旦我们有了这一点,我们写出来JObject的JsonWriter。这是代码:
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(); } }
现在我们有了转换器,但是要注意的是,我们不能简单地Document使用[JsonConverter]属性装饰类以使用它。如果这样做的话,最终会导致递归循环,因为在将文档加载到中时,转换器会尝试使用自身JObject。因此,我们需要创建转换器的实例,然后通过设置将其传递给串行器。转换器的CanConvert方法可确保将其用于正确的类。该JObject.FromObject方法在内部使用其他序列化器实例,因此不会看到DocumentConverter,因此不会遇到麻烦。
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" }