JNY*_*ger 14 c# serialization json json.net
我正在使用JSON.NET来序列化我的对象以连接到REST API.我的对象中需要序列化为JSON的属性之一具有动态属性名称.如果此属性的struct中包含的值是数值,则JSON属性为"type_id",但如果此值为字符串值,则JSON属性名称为"type_code".我尝试使用自定义JsonConverter,但是JsonWriterException当我尝试序列化时,我收到了这条消息:
"状态属性中的Token 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; }
Run Code Online (Sandbox Code Playgroud)
在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);
}
Run Code Online (Sandbox Code Playgroud)
但是,我假设它默认为对象属性的名称而不是我的自定义属性,导致JSON字符串中的单个值的两个属性名称.如何为此动态设置属性名称,因为JsonPropertyAttribute标记在未明确指定时会显示拉取对象的属性名称?
注意:此对象永远不需要从此应用程序反序列化.
编辑: 此对象标记有[JsonObject(MemberSerialization.OptIn)]属性
Bri*_*ers 22
A JsonConverter不能在父对象中设置属性的名称.WriteJson调用转换器的方法时,属性名称已写入JSON; 作者期待只有一个值.这就是你收到错误的原因.为了使其工作,必须为父对象创建自定义转换器.然后,该转换器将负责编写其子项的属性名称和值.
跟进
可以为父对象编写转换器,以便仍然遵循应用于它的JSON属性,同时仍然可以实现所需的结果.我将概述下面的方法.
首先,一点点设置.既然你没有说出你的类叫什么,我会假设这个例子被调用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; }
}
Run Code Online (Sandbox Code Playgroud)
您也没有显示TypeIdentifier该类的代码,因此我只是假设它看起来像这样,例如:
class TypeIdentifier
{
public string Value { get; set; }
public string ParameterName { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
有了这个,我们可以制作转换器.这种方法相当简单:我们将其加载Document到a中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();
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们有了转换器,但是我们不能简单地Document使用[JsonConverter]属性来装饰类以便使用它.如果我们这样做,我们最终会得到一个递归循环,因为当我们将文档加载到转换器中时,转换器会尝试使用它自己JObject.因此,我们需要创建转换器的实例并通过设置将其传递给序列化器.转换器的CanConvert方法确保它在正确的类上使用.该JObject.FromObject方法在内部使用不同的序列化程序实例,因此它看不到DocumentConverter,因此不会遇到麻烦.
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new DocumentConverter());
string json = JsonConvert.SerializeObject(doc, settings);
Run Code Online (Sandbox Code Playgroud)
这是一个演示转换器的演示:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
以下是上述输出:
{
"title": "How to write a JSON converter",
"type_id": "26",
"date": "2014-03-28T00:00:00-05:00"
}
Run Code Online (Sandbox Code Playgroud)