在WCF中怎么实现接口反序列化和序列化为JSON
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在WCF中怎么实现接口反序列化和序列化为JSON相关的知识,希望对你有一定的参考价值。
参考技术A 截止至.NET4.0总共有如下若干个序列化类
1.xml序列化
XmlSerializer
2.二进制序列化
BinaryFormatter
3.Soap序列化
SoapFormatter
4.WCF序列化
DataContractSerializer
5.Json序列化
DataContractJsonSerializer和javascriptSerializer
如何使用 JSON.NET 反序列化为嵌套/递归字典和列表?
【中文标题】如何使用 JSON.NET 反序列化为嵌套/递归字典和列表?【英文标题】:How do I use JSON.NET to deserialize into nested/recursive Dictionary and List? 【发布时间】:2011-07-29 14:28:52 【问题描述】:我需要将复杂的 JSON blob 反序列化为标准 .NET 容器,以便在不了解 JSON 的代码中使用。它希望事物采用标准 .NET 类型,特别是 Dictionary<string, object>
或 List<object>
,其中“对象”可以是原始的或递归的(字典或列表)。
我不能使用静态类型来映射结果并且 JObject/JToken 不适合。理想情况下,会有某种方式(也许是通过合同?)将原始 JSON 转换为基本的 .NET 容器。
我已经到处寻找任何方法来诱使 JSON.NET 反序列化器在遇到“”或“[]”时创建这些简单类型,但收效甚微。
任何帮助表示赞赏!
【问题讨论】:
我尝试了 System.Web.Script.Serialization.JavaScriptSerializer,在这种情况下它可以满足我的要求,但我还有其他原因想要坚持使用 JSON.NET。 更新:我现在做的是在CreateJObject和CreateJToken方法中下载并修改Json.NET的源代码来创建我想要的类型。有 8-10 个单元测试需要修复,但我可以接受由此产生的妥协。 对于它的价值,问题源于 JsonSerializerInternalReader 中 HasDefinedType 方法的用户。 HasDefinedType 检查是在之前咨询有关如何创建目标对象的合同,即使它确实尝试过,在知道是否“”之前就已经做出了关于合同的决定或“[]”在起作用。我认为有一些重构是为了让 Json.NET 将这个决定外部化,并允许用户代码在“对象”是已知的情况下确定目标类型。 为什么@brian-rogers 的答案不被接受为最佳答案? @IgnacioCalvo:因为这个问题很明显是针对旧版本的 Netwonsoft.Json 还不能做到的。 【参考方案1】:您可以使用自定义JsonConverter
完全控制类型的序列化。 http://james.newtonking.com/projects/json/help/html/T_Newtonsoft_Json_JsonConverter.htm 的文档。
另外,根据this blog post,您需要将JArray
用于列表,将JObject
用于字典。
【讨论】:
感谢您的提示。我需要处理基于 JSON 的对象的反序列化:“”需要创建一个 Dictionary[string, object] 而“[]”需要创建一个 List[object] 或纯 object[]。我看不到如何将 JsonCoverter 连接到这个问题。当目标类型为“对象”时,即使在反序列化器使用合同之前,反序列化器中似乎也存在一些硬编码逻辑。 覆盖合约解析器以连接自定义转换器 谢谢,但我已经尝试过了。当类型属于反序列化器中的“!HasDefinedType”检查时,不使用合同。访问 JsonSerializerInternalReader.cs 并搜索 HasDefinedType。您会在合约委托上方看到对该方法的调用,如果类型是“对象”,则它会被此检查捕获。【参考方案2】:我喜欢 AutoMapper,似乎认为它可以解决很多问题......就像这个......
为什么不让 JSON.NET 将事物转换为它想要的任何东西......并使用AutoMapper 将其映射到您真正想要的对象中。
除非性能是最重要的,否则这个额外的步骤应该是值得的,因为它可以降低复杂性并能够使用所需的序列化程序。
【讨论】:
谢谢,我会调查的。但我仍然希望找到 JSON.NET 原生的东西,因为当遇到“”到“对象”或“[]”到对象时,它必须创建一些东西。在这种情况下,我只是看不到如何控制它创建的对象的类型。【参考方案3】:你不能按照我的要求去做。至少在经过大量研究后,我无法判断。我不得不编辑 Json.NET 的源代码。
【讨论】:
此更改是否有可能被推回源或任何地方可用? 我有一个类似的问题,我的字典值有时包含数组(基本上是“[]”)。我第一次遇到这个问题,但很难理解为什么还没有以通用的方式解决这个问题。这似乎是一个非常基本的问题,这是一个死胡同。任何人都想插话并解释 JSON 反序列化 (JSON.NET) 的主要问题是什么?其他人是否可以控制他们的 JSON 并“更好”地构建它,或者我们在这里缺少什么?【参考方案4】:如果您只想要一个可以处理任意 JSON 并将其转换为常规 .NET 类型(基元、列表和字典)的嵌套结构的通用方法,您可以使用 JSON.Net 的LINQ-to-JSON API 来实现:
using System.Linq;
using Newtonsoft.Json.Linq;
public static class JsonHelper
public static object Deserialize(string json)
return ToObject(JToken.Parse(json));
public static object ToObject(JToken token)
switch (token.Type)
case JTokenType.Object:
return token.Children<JProperty>()
.ToDictionary(prop => prop.Name,
prop => ToObject(prop.Value));
case JTokenType.Array:
return token.Select(ToObject).ToList();
default:
return ((JValue)token).Value;
您可以调用如下所示的方法。 obj
将包含 Dictionary<string, object>
、List<object>
或原语,具体取决于您开始使用的 JSON。
object obj = JsonHelper.Deserialize(jsonString);
【讨论】:
希望你不介意。我使用 LINQ 编辑了代码以使其更紧凑。 @bradgonesurfing 我喜欢! 如何在 vb.net 中做 token.Select 行? @NullVoxPopulitoken.Select(AddressOf ToObject).ToList()
@JimmyHuch 你还需要using System.Linq
。【参考方案5】:
使用 JSON.NET 将 json 字符串递归反序列化为字典和列表的一种方法是创建一个自定义 json 转换器类,该类派生自 JSON.NET 提供的 JsonConverter
抽象类。
它在您的派生JsonConverter
中,您可以在其中放置对象应如何写入和从 json 写入的实现。
您可以像这样使用您的自定义JsonConverter
:
var o = JsonConvert.DeserializeObject<IDictionary<string, object>>(json, new DictionaryConverter());
这是我过去成功使用的自定义 JsonConverter,以实现与您在问题中概述的相同目标:
public class DictionaryConverter : JsonConverter
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) this.WriteValue(writer, value);
private void WriteValue(JsonWriter writer, object value)
var t = JToken.FromObject(value);
switch (t.Type)
case JTokenType.Object:
this.WriteObject(writer, value);
break;
case JTokenType.Array:
this.WriteArray(writer, value);
break;
default:
writer.WriteValue(value);
break;
private void WriteObject(JsonWriter writer, object value)
writer.WriteStartObject();
var obj = value as IDictionary<string, object>;
foreach (var kvp in obj)
writer.WritePropertyName(kvp.Key);
this.WriteValue(writer, kvp.Value);
writer.WriteEndObject();
private void WriteArray(JsonWriter writer, object value)
writer.WriteStartArray();
var array = value as IEnumerable<object>;
foreach (var o in array)
this.WriteValue(writer, o);
writer.WriteEndArray();
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
return ReadValue(reader);
private object ReadValue(JsonReader reader)
while (reader.TokenType == JsonToken.Comment)
if (!reader.Read()) throw new JsonSerializationException("Unexpected Token when converting IDictionary<string, object>");
switch (reader.TokenType)
case JsonToken.StartObject:
return ReadObject(reader);
case JsonToken.StartArray:
return this.ReadArray(reader);
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
case JsonToken.Boolean:
case JsonToken.Undefined:
case JsonToken.Null:
case JsonToken.Date:
case JsonToken.Bytes:
return reader.Value;
default:
throw new JsonSerializationException
(string.Format("Unexpected token when converting IDictionary<string, object>: 0", reader.TokenType));
private object ReadArray(JsonReader reader)
IList<object> list = new List<object>();
while (reader.Read())
switch (reader.TokenType)
case JsonToken.Comment:
break;
default:
var v = ReadValue(reader);
list.Add(v);
break;
case JsonToken.EndArray:
return list;
throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
private object ReadObject(JsonReader reader)
var obj = new Dictionary<string, object>();
while (reader.Read())
switch (reader.TokenType)
case JsonToken.PropertyName:
var propertyName = reader.Value.ToString();
if (!reader.Read())
throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
var v = ReadValue(reader);
obj[propertyName] = v;
break;
case JsonToken.Comment:
break;
case JsonToken.EndObject:
return obj;
throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
public override bool CanConvert(Type objectType) return typeof(IDictionary<string, object>).IsAssignableFrom(objectType);
这是f#
中的等价物:
type IDictionaryConverter() =
inherit JsonConverter()
let rec writeValue (writer: JsonWriter) (value: obj) =
let t = JToken.FromObject(value)
match t.Type with
| JTokenType.Object -> writeObject writer value
| JTokenType.Array -> writeArray writer value
| _ -> writer.WriteValue value
and writeObject (writer: JsonWriter) (value: obj) =
writer.WriteStartObject ()
let obj = value :?> IDictionary<string, obj>
for kvp in obj do
writer.WritePropertyName kvp.Key
writeValue writer kvp.Value
writer.WriteEndObject ()
and writeArray (writer: JsonWriter) (value: obj) =
writer.WriteStartArray ()
let array = value :?> IEnumerable<obj>
for o in array do
writeValue writer o
writer.WriteEndArray ()
let rec readValue (reader: JsonReader) =
while reader.TokenType = JsonToken.Comment do
if reader.Read () |> not then raise (JsonSerializationException("Unexpected token when reading object"))
match reader.TokenType with
| JsonToken.Integer
| JsonToken.Float
| JsonToken.String
| JsonToken.Boolean
| JsonToken.Undefined
| JsonToken.Null
| JsonToken.Date
| JsonToken.Bytes -> reader.Value
| JsonToken.StartObject -> readObject reader Map.empty
| JsonToken.StartArray -> readArray reader []
| _ -> raise (JsonSerializationException(sprintf "Unexpected token when reading object: %O" reader.TokenType))
and readObject (reader: JsonReader) (obj: Map<string, obj>) =
match reader.Read() with
| false -> raise (JsonSerializationException("Unexpected end when reading object"))
| _ -> reader.TokenType |> function
| JsonToken.Comment -> readObject reader obj
| JsonToken.PropertyName ->
let propertyName = reader.Value.ToString ()
if reader.Read() |> not then raise (JsonSerializationException("Unexpected end when reading object"))
let value = readValue reader
readObject reader (obj.Add(propertyName, value))
| JsonToken.EndObject -> box obj
| _ -> raise (JsonSerializationException(sprintf "Unexpected token when reading object: %O" reader.TokenType))
and readArray (reader: JsonReader) (collection: obj list) =
match reader.Read() with
| false -> raise (JsonSerializationException("Unexpected end when reading array"))
| _ -> reader.TokenType |> function
| JsonToken.Comment -> readArray reader collection
| JsonToken.EndArray -> box collection
| _ -> collection @ [readValue reader] |> readArray reader
override __.CanConvert t = (typeof<IDictionary<string, obj>>).IsAssignableFrom t
override __.WriteJson (writer:JsonWriter, value: obj, _:JsonSerializer) = writeValue writer value
override __.ReadJson (reader:JsonReader, _: Type, _:obj, _:JsonSerializer) = readValue reader
【讨论】:
谢谢。它解决了一半的挑战。后半部分不是使用 C# 对象,而是使用 MatLab MWArray 派生对象。在这里我可以访问每个值和它的属性名称,所以从这里看起来就像一条直路。以上是关于在WCF中怎么实现接口反序列化和序列化为JSON的主要内容,如果未能解决你的问题,请参考以下文章
将 Objective-C 对象序列化和反序列化为 JSON