bru*_*ida 3 c# xml json json.net asp.net-web-api
在我的数据库中,我有一个包含许多列的表,其中一个包含一个JSON字符串(我无法控制它).像这样的东西:
Name Age ExtraData
---- --- ------------------
Bob 31 {c1: "1", c2: "2"} <-- string with JSON
Run Code Online (Sandbox Code Playgroud)
我的Web API端点必须根据请求中的Accept标头返回XML或JSON.像这样的东西:
JSON:
{
"Name": "Bob",
"Age": 31,
"ExtraData": {
"c1": 1,
"c2": 2
}
}
Run Code Online (Sandbox Code Playgroud)
XML:
<person>
<Name>Bob</Name>
<Age>31</Age>
<ExtraData>
<c1>1</c1>
<c2>2</c2>
</ExtraData>
</person>
Run Code Online (Sandbox Code Playgroud)
为此,我在C#中创建了一个类,如下所示:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Object ExtraData { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
从数据库解析数据时,我将填写ExtraData如下:
personInstance.ExtraData = JsonConvert.DeserializeObject(personTableRow.ExtraData);
Run Code Online (Sandbox Code Playgroud)
当Web API返回JSON时,所有工作都按预期工作.
当Web API返回XML时,它会给出一个异常:
'ObjectContent`1'类型无法序列化内容类型'application/xml的响应主体; 字符集= UTF-8' .
内部异常是这样的(它不是英文):
Newtonsoft.Json.Linq.JToken有一个循环引用,不支持.(Otipo'Newtonsoft.Json.Linq.JToken'éumcontrato de dadosdecoleçãorecursivaquenãoésurportado.考虑修改一个definiçãodacoleção'Newtonsoft.Json.Linq.JToken'pararemoverreferênciasassima.)
有没有办法在没有循环引用的情况下将JSON数据解析为对象?
你遇到了限制XmlSerializer.当将JSON对象(由大括号包围的无序的名称/值对集合)反序列化为ac#时object,Json.NET会创建一个类型的对象JObject,但遗憾的XmlSerializer是不知道如何序列化JObject.特别是它陷入无限递归,试图序列化的孩子们JToken.Parent.因此,您需要将底层转换为可以处理object ExtraData的类型XmlSerializer.
但是,使用什么类型并不明显,因为:
用于表示JSON对象的最自然的c#类型是字典,XmlSerializer不支持字典.
XmlSerializer通过静态类型发现工作.object必须通过声明可能遇到的所有多态子类型[XmlInclude(typof(T))].但是,如果这样做,XML将包含实际类型作为您在XML中似乎不需要的xsi:type属性.
你可以做的是利用这个[XmlAnyElement]功能来创建一个代理属性,使用Json.NET 将你的转换object ExtraData为:XElementXmlNodeConverter
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
[XmlIgnore]
[JsonProperty]
public object ExtraData { get; set; }
[XmlAnyElement("ExtraData")]
[JsonIgnore]
public XElement ExtraDataXml
{
get
{
return JsonExtensions.SerializeExtraDataXElement("ExtraData", ExtraData);
}
set
{
ExtraData = JsonExtensions.DeserializeExtraDataXElement("ExtraData", value);
}
}
}
public static class JsonExtensions
{
public static XElement SerializeExtraDataXElement(string name, object extraData)
{
if (extraData == null)
return null;
var token = JToken.FromObject(extraData);
if (token is JValue)
{
return new XElement(name, (string)token);
}
else if (token is JArray)
{
return new JObject(new JProperty(name, token)).ToXElement(false, name, true);
}
else
{
return token.ToXElement(false, name, true);
}
}
public static object DeserializeExtraDataXElement(string name, XElement element)
{
object extraData;
if (element == null)
extraData = null;
else
{
extraData = element.ToJToken(true, name, true);
if (extraData is JObject)
{
var obj = (JObject)extraData;
if (obj.Count == 1 && obj.Properties().First().Name == name)
extraData = obj.Properties().First().Value;
}
if (extraData is JValue)
{
extraData = ((JValue)extraData).Value;
}
}
return extraData;
}
public static XElement ToXElement(this JToken obj, bool omitRootObject, string deserializeRootElementName, bool writeArrayAttribute)
{
if (obj == null)
return null;
using (var reader = obj.CreateReader())
{
var converter = new Newtonsoft.Json.Converters.XmlNodeConverter() { OmitRootObject = omitRootObject, DeserializeRootElementName = deserializeRootElementName, WriteArrayAttribute = writeArrayAttribute };
var jsonSerializer = JsonSerializer.CreateDefault(new JsonSerializerSettings { Converters = { converter } });
return jsonSerializer.Deserialize<XElement>(reader);
}
}
public static JToken ToJToken(this XElement xElement, bool omitRootObject, string deserializeRootElementName, bool writeArrayAttribute)
{
// Convert to Linq to XML JObject
var settings = new JsonSerializerSettings { Converters = { new XmlNodeConverter { OmitRootObject = omitRootObject, DeserializeRootElementName = deserializeRootElementName, WriteArrayAttribute = writeArrayAttribute } } };
var root = JToken.FromObject(xElement, JsonSerializer.CreateDefault(settings));
return root;
}
}
Run Code Online (Sandbox Code Playgroud)
使用上面的类,我可以反序列化您的JSON并序列化为XML,结果如下:
<Person>
<Name>Bob</Name>
<Age>31</Age>
<ExtraData>
<c1>1</c1>
<c2>2</c2>
</ExtraData>
</Person>
Run Code Online (Sandbox Code Playgroud)
请注意,JSON和XML之间存在导致问题的不一致:
JSON原始值是"轻微"类型(如字符串,数字,布尔值或null),而XML文本是完全无类型的.因此,JSON中的数值(和日期)作为字符串进行往返XML.
XML没有数组的概念.因此,其根容器是数组的JSON需要在序列化期间添加合成根元素.这会在转换过程中增加一些代码味道.
XML必须具有单个根元素,而有效JSON可以包含原始值,例如字符串.转换期间还需要合成的根元素.
在这里轻轻测试的原型小提琴,在那里我演示代码适用于ExtraData它是一个JSON对象,一个字符串数组,一个字符串和一个null值.
| 归档时间: |
|
| 查看次数: |
651 次 |
| 最近记录: |