WCF JSON 反序列化中的空格问题
我有一个 WCF REST 服务,它接受自定义 DataContract 参数作为 JSON,可以是超类型或子类型。当我传递包含额外空格的 JSON 时,该对象始终反序列化为超类型。当我从 JSON 中删除所有空格时,对象会反序列化为子类型。
这是一个示例:
[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 个数据包之间是不同的:
<!-- First packet, deserializes to SuperClass -->
<root type="object">
<__type type="string">SubClass:#WhitespaceTest</__type>
<Message type="string">Message</Message>
<Extra type="string">Extra</Extra>
</root>
<!-- Second packet, deserializes to SubClass -->
<root type="object" __type="SubClass:#WhitespaceTest">
<Message type="string">Message</Message>
<Extra type="string">Extra</Extra>
</root>
因此,空白似乎混淆了 JSON 反序列化器。有谁知道为什么会发生这种情况以及我能做些什么?
I have a WCF REST service that accepts a custom DataContract argument as JSON which may either by the super-type or a sub-type. When I pass JSON containing extra whitespace, the object always deserializes as the super-type. When I strip all whitespace from the JSON, the object deserializaes as the sub-type.
Here is an example:
[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");
}
}
}
If I send the following message, the service will print 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" }
I get the same result if I "pretty print" the packet as well so that the JSOn is split over multiple lines. However, the service will print SubClass
if I strip the whitespace as follows:
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"}
I've debugged the output of System.ServiceModel.OperationContext.Current.RequestContext.RequestMessage.ToString()
and noticed that the XML generated from the JSON is different between the 2 packets:
<!-- First packet, deserializes to SuperClass -->
<root type="object">
<__type type="string">SubClass:#WhitespaceTest</__type>
<Message type="string">Message</Message>
<Extra type="string">Extra</Extra>
</root>
<!-- Second packet, deserializes to SubClass -->
<root type="object" __type="SubClass:#WhitespaceTest">
<Message type="string">Message</Message>
<Extra type="string">Extra</Extra>
</root>
So, it seems as though the whitespace confuses the JSON deserializer. Does anyone know why this happens and what I can do about it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是一个已知问题,已在 4.5 框架中修复。不幸的是,如果您想在当前框架版本中使用多态性,您实际上需要去除对象前面的空白。一种方法是使用 JsonReaderWriterFactory 创建的读取器/写入器读取/写入 JSON,因为它将去除元素周围的空格(或任何漂亮的打印)。
This is a known issue which was fixed in the 4.5 framework. Unfortunately you essentially need to strip the white spaces from the front of the object if you want to use polymorphism in the current framework version. One way to do that is to read / write the JSON using a reader / writer created by
JsonReaderWriterFactory
, as it will strip the white spaces (or any pretty printing) around the elements.不幸的是,我对此没有很好的答案。我们遇到了同样的问题并联系了微软。他们坚持认为,由于性能问题,他们所做的事情是可以的,考虑到整个管道的工作方式,这是可笑的。
所以我们的经验是,许多地方的空白会导致问题。另外,如果将 __type 字段放在除第一个字段之外的任何位置,您将获得超类型。
我的建议是看看其他 JSON 解决方案。不幸的是我不知道替代方案或者我会建议一些东西。
编辑: 正如 carlosfigueira 指出的,这个问题显然已在 4.5 中得到修复。我还没有在那里尝试过。
Unfortunately, I have no good answer to this. We ran into the same issue and contacted Microsoft about it. They insisted that what they were doing was okay because of performance concerns, which is laughable considering how the entire pipeline works.
So our experience has been that whitespace in many places causes issues. Also, if you put the __type field anywhere but the first, you'll get the supertype.
My advice would be to look at other solutions to JSON. Unfortunately I'm not up on the alternatives or I'd suggest something.
Edit: As carlosfigueira points out, this has apparently been fixed in 4.5. I have not tried it there as of yet.