如何拥有一个带有 json 动态成员的 WCF DataContract
Posted
技术标签:
【中文标题】如何拥有一个带有 json 动态成员的 WCF DataContract【英文标题】:How to have a WCF DataContract with a json dynamic member 【发布时间】:2012-10-06 16:20:19 【问题描述】:在我正在进行的项目中,我们需要有一个可以包含一些未定义 JSON 的 DataContract。
DataMember 是一些仅对客户端有意义的 JSON。我们希望允许客户端向我们发送我们不知道的 json。
例子:
public class Contract
[DataMember]
public int clientId;
[DataMember]
public string json;
显然,定义这样的合同需要客户端像这样转义 json:
"clientId":1,
"json": "\"test\":\"json\""
显然,这不是我们需要的。客户端应该发送给我们的 json 应该是这样的:
"clientId":1,
"json": "test":"json"
我们调查的可能解决方案:
-
使用 Stream 作为请求正文的合同参数。工作,但把工作放在我们这边,而不是使用框架。
将“json”定义为动态对象。不工作。无法正确写入属性。
使用 Newtonsoft 库,更改 WCF 端点中的默认合同序列化程序,以将所有输入序列化为 JObject。我们还需要处理请求的序列化,这会导致我们的应用程序出现问题。我们宁愿避免这种方式。
有没有人可以解决这个问题?
编辑
该服务提供其他 json 资源。它使用 webHttpBinding 定义了一个端点。 操作是这样定义的(为了简单起见):
[WebInvoke(Method = "POST", UriTemplate = "...", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
[OperationContract]
Stream Create(Contract c);
此外,该服务使用以下属性进行装饰:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
谢谢。 杰夫
【问题讨论】:
听起来您的客户端正在将您的服务输出作为soap/XML 使用,并且您正试图通过soap 消息传输JSON 字符串。您是否考虑过为soap/XML 和JSON 响应保留单独的端点。您可以将标准 DataContact 端点按原样保留在当前绑定中,并添加一个新的WebHttpBinding
端点以使用 JSON 字符串进行响应。是的,它增加了一个调用,但它会简化你的合同。
@Sixto Saez:我们不提供肥皂。我们有 1 个带有 webHttpBinding 的端点,仅支持 REST json。
您会使用客户端在请求中发送的未定义 JSON 吗?
【参考方案1】:
WCF(从 4.5 开始)不支持将任意 JSON 作为数据协定的一部分进行反序列化。您需要使用另一个序列化程序来执行此操作 - JSON.NET 是我个人喜欢的一个。为了能够更改序列化程序,您可以使用不同的消息格式化程序,在https://github.com/microsoftarchive/msdn-code-gallery-community-s-z/tree/master/Supporting%20different%20data%20and%20serialization%20formats%20in%20WCF 的帖子中,我有一个完全可以做到这一点的示例 - 将 WCF 使用的默认序列化替换为 JSON.NET。
请注意,要使用该库接收任意 JSON,您需要将“json”属性的类型更改为 JSON.NET 中的任意 JSON,JToken:
public class Contract
[DataMember]
public int clientId;
[DataMember]
public Newtonsoft.Json.Linq.JToken json;
【讨论】:
嗨,Carlos,在问这个问题之前,我已经在你的博客上看了很多关于我的问题。 ;) 我已经尝试过这条路线,实现了我自己的消息格式化程序,但它在我们的应用程序中暗示了一些问题。如果可能的话,我想找到另一种方法。否则,我最终会更改格式化程序。顺便说一句,感谢您的博客,在过去的几个月里,我阅读了很多关于 WCF 可扩展性的帖子。 链接失效了我把它改成微软官方 GitHub 存档的 Msdn 博客存档。在这种情况下,它比 Web 存档链接更好,因为它也提供了整个代码解决方案【参考方案2】:你用这些标签配置了类和方法吗? 类实施前
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class xxx ...
方法实现之前
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public Contract getContract() ...
【讨论】:
AspNetCompatibilityRequirements 属性在我们的合约实例上,操作使用 [OperationContract] 和 [WebInvoke(Method = "POST" UriTemplate="....", ResponseFormat = WebMessageFormat.Json , RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare 往返可以将名为“json”的类属性声明为对象而不是字符串。该对象必须是包含一个唯一属性的类: public string test get;set;【参考方案3】:你试过了吗?
public class Contract
[DataMember]
public int clientId;
[DataMember]
public Dictionary<string,string> DynamicProperties;
【讨论】:
这只会给出平面对象...想想students:[name:"john", grade:54,name:"michelle", grade:95], class:"Eco 1o1"
【参考方案4】:
更改签名以接受流。 例如:
public String ProcessJson(Stream jsondata)
//play with jsondata
要作为流接收,请覆盖 WebContentTypeMapper 方法。
public class RawWebContentTypeMapper : WebContentTypeMapper
public override WebContentFormat GetMessageFormatForContentType(string contentType)
return WebContentFormat.Raw;
【讨论】:
【参考方案5】:您不希望“json”属性包含字符串,而是希望它包含对象。像这样:
public class Contract
[DataMember]
public int clientId;
[DataMember]
public JsonObj json;
public class JsonObj
[DataMember]
public string test;
这样 json 解析器就会输出你需要的东西。 我希望我说清楚了。
干杯!
【讨论】:
不幸的是,这行不通。对于客户端它可以工作,但另一个可能会发布一些完全不同的 json。一些像:“clientId”:1,“json”:“id”:13,“ref”:“theOther”以上是关于如何拥有一个带有 json 动态成员的 WCF DataContract的主要内容,如果未能解决你的问题,请参考以下文章
使用 JSON 实现带有 WCF 服务 (wshttpBinding) 的 c# asp.net 应用程序
WCF POST 通过 JQuery。如何在 JSON 中发送数组?
在 WCF Azure 服务总线中动态分配 json 响应内容类型