使用 WCF 将类序列化为 xsd.exe 生成的 JSON
Posted
技术标签:
【中文标题】使用 WCF 将类序列化为 xsd.exe 生成的 JSON【英文标题】:Serializing a class to JSON generated by xsd.exe using WCF 【发布时间】:2016-05-29 04:51:19 【问题描述】:我想用 WCF 编写一个 RESTful Web 服务,它能够以 JSON 和 XML 回复。我有一个 XML 模式,我使用xsd.exe
从中生成了我的类。只要我请求 XML,一切都可以正常工作,但如果我想要 JSON 作为响应,它就会失败。
System.ServiceModel.Dispatcher.MultiplexingDispatchMessageFormatter
抛出 System.Collections.Generic.KeyNotFoundException
。问题是,到目前为止,我发现xsd.exe
不会生成DataContract
和DataMember
属性。有没有什么解决方案我不需要使用SvcUtil.exe
,因为因此我需要更改我的架构..
那是它失败的代码,JsonDispatchMessageFormatter
的类型是MultiplexingDispatchMessageFormatter
。 (反正这是默认类型)
var headers = requestProperty.Headers[HttpRequestHeader.Accept] ?? requestProperty.Headers[HttpRequestHeader.ContentType];
if (headers != null && headers.Contains("application/json"))
return this.JsonDispatchMessageFormatter.SerializeReply(messageVersion, parameters, result);
生成的代码:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="...")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="...", IsNullable=false)]
public partial class Incident
private long incidentIdField;
/// <remarks/>
public long IncidentId
get
return this.incidentIdField;
set
this.incidentIdField = value;
【问题讨论】:
在重新调整之前尝试添加WebOperationContext.Current.OutgoingResponse.ContentType = "application/json";
将"application/json"
添加到传出响应中允许我现在序列化为json,但我还有一个问题。 XML 和 JSON 都序列化支持字段而不是属性。我可以为我的服务合同使用属性XmlSerializerFormat
来避免XML 的这种情况,但是我再次不能使用JSON,因为它不喜欢这个属性。它建议我使用DataContractFormatAttribute
,这将再次导致序列化支持字段..
【参考方案1】:
您在 JSON 中看到私有字段而不是公共属性的原因是 xsd.exe
已将您的类标记为 [SerializableAttribute]
。当此属性应用于一个类型时,它表示该类型的实例可以通过序列化所有私有和公共字段来序列化——而不是属性。
在幕后,WCF 使用DataContractJsonSerializer
与 JSON 进行序列化。当此序列化程序为没有data contract attributes 的类型生成默认的隐式数据协定时,它会注意到[Serializable]
属性并尊重它,生成一个对公共和私有字段进行序列化和反序列化的协定。这就是你所看到的。
有点奇怪的是xsd.exe
不需要将[Serializable]
添加到其生成的类中。 XmlSerializer
完全忽略此属性,因为它只能序列化公共成员。 (它也完全忽略了数据契约属性。同样,数据契约序列化器都忽略了XmlSerializer
control attributes。)
不幸的是,我没有看到任何xsd
command line switches 来禁用此属性。因此,您将进行某种手动修复:
从生成的类中删除 [System.SerializableAttribute()]
。除非您在某处使用BinaryFormatter
,否则这应该是无害的;你可能不是。
将[DataContract]
和[DataMember]
属性添加到生成的类中。 (请记住,XmlSerializer
已忽略这些,因此您预先存在的 XML 架构将保持不变。)
您还可以考虑使用SvcUtil.exe
生成符合合同的类,然后使用automapper 将旧类映射到新类。
或者您可以考虑切换到不同的 JSON 序列化程序,例如 json.net,您可以在其中 control whether to ignore or respect [Serializable]
。 How to set Json.Net as the default serializer for WCF REST service 和 C# WCF REST - How do you use JSON.Net serializer instead of the default DataContractSerializer? 的问题应该可以帮助您入门。
顺便说一句,如果您想精确控制 XML 和 JSON 格式,WCF rest 可能不是最适合您的技术。 ASP.NET Web API 允许使用json.net 更精确地控制序列化格式;请参阅 JSON and XML Serialization in ASP.NET Web API 以及 Setting IgnoreSerializableAttribute Globally in Json.net 和 .NET WebAPI Serialization k_BackingField Nastiness。
【讨论】:
以上是关于使用 WCF 将类序列化为 xsd.exe 生成的 JSON的主要内容,如果未能解决你的问题,请参考以下文章
WinRT 与 xsd.exe 生成的序列化/无权访问 System.Xml.XmlNode