Whitespace的WCF JSON反序列化问题

我有一个WCF REST服务,它接受一个自定义DataContract参数作为JSON,可以是超类型或子类型。 当我传递包含额外空格的JSON时,对象总是反序列化为超类型。 当我从JSON中删除所有空格时,对象deserializaes作为子类型。

这是一个例子:

[DataContract] [KnownType(typeof(SubClass))] public class SuperClass { [DataMember] public string Message { get; set; } } [DataContract] public class SubClass : SuperClass { [DataMember] public string Extra { get; set; } } [ServiceContract] public interface IService1 { [OperationContract] [WebInvoke] void LogMessage(SuperClass arg); } public class Service1 : IService1 { public void LogMessage(SuperClass arg) { if (arg is SubClass) { Debug.WriteLine("SubClass"); } else if (arg is SuperClass) { Debug.WriteLine("SuperClass"); } } } 

如果我发送以下消息,该服务将打印SuperClass

 POST http://localhost:5763/Service1.svc/LogMessage HTTP/1.1 User-Agent: Fiddler Content-Type: text/json Host: localhost:5763 Content-Length: 86 { "__type":"SubClass:#WhitespaceTest", "Message":"Message", "Extra":"Extra" } 

如果我“打印”数据包,那么我得到相同的结果,以便JSOn分成多行。 但是,如果我按如下方式删除空格,服务将打印SubClass

 POST http://localhost:5763/Service1.svc/LogMessage HTTP/1.1 User-Agent: Fiddler Content-Type: text/json Host: localhost:5763 Content-Length: 73 {"__type":"SubClass:#WhitespaceTest","Message":"Message","Extra":"Extra"} 

我已经调试了System.ServiceModel.OperationContext.Current.RequestContext.RequestMessage.ToString()的输出,并注意到从JSON生成的XML在2个数据包之间是不同的:

   SubClass:#WhitespaceTest Message Extra    Message Extra  

因此,似乎空白混淆了JSON反序列化器。 有谁知道为什么会发生这种情况以及我能做些什么呢?

这是一个已知问题,已在4.5框架中修复。 不幸的是,如果要在当前框架版本中使用多态,则基本上需要从对象的前面剥离空白区域。 一种方法是使用由JsonReaderWriterFactory创建的读取器/写入器来读取/写入JSON,因为它将剥离元素周围的空白区域(或任何漂亮的打印)。

 public class StackOverflow_8661714 { [DataContract(Name = "SuperClass", Namespace = "WhitespaceTest")] [KnownType(typeof(SubClass))] public class SuperClass { [DataMember] public string Message { get; set; } } [DataContract(Name = "SubClass", Namespace = "WhitespaceTest")] public class SubClass : SuperClass { [DataMember] public string Extra { get; set; } } public static void Test() { string originalJson = "{ \"__type\":\"SubClass:WhitespaceTest\", \"Message\":\"Message\", \"Extra\":\"Extra\" }"; byte[] originalJsonBytes = Encoding.UTF8.GetBytes(originalJson); MemoryStream writeStream = new MemoryStream(); XmlDictionaryWriter jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(writeStream, Encoding.UTF8, false); XmlDictionaryReader jsonReader = JsonReaderWriterFactory.CreateJsonReader(originalJsonBytes, 0, originalJsonBytes.Length, XmlDictionaryReaderQuotas.Max); jsonWriter.WriteNode(jsonReader, true); jsonWriter.Flush(); Console.WriteLine(Encoding.UTF8.GetString(writeStream.ToArray())); writeStream.Position = 0; DataContractJsonSerializer dcjs = new DataContractJsonSerializer(typeof(SuperClass), new Type[] { typeof(SubClass) }); object o = dcjs.ReadObject(writeStream); Console.WriteLine(o); } } 

不幸的是,我对此没有好的答案。 我们遇到了同样的问题,并就此与微软联系。 他们坚持认为他们正在做的事情是好的,因为考虑到整个管道是如何工作的,这是可笑的。

所以我们的经验是,很多地方的空白都会引起问题。 此外,如果您将__type字段放在除第一个之外的任何位置,您将获得超类型。

我的建议是查看JSON的其他解决方案。 不幸的是,我没有选择其他选择,或者我会提出一些建议。

编辑:正如carlosfigueira指出的那样,这显然已在4.5中得到修复。 到目前为止我还没有尝试过。