如何在WCF Rest Service中创建JSON以匹配/序列化为DataContract

接口:

namespace SQRT_WCF { [DataContract] public class PlaceOrder { [DataMember] public string claimID { get; set; } [DataMember] public string rederenceDate { get; set; } } } 

调用C#方法:

 public SQ_jsonModel.Response placeOrder(PlaceOrder argPlaceOrderJSON) { ... } 

我已将我的web服务附加到工作进程,并跟踪代码。 到目前为止,我尝试过的所有内容,变量argPlaceOrderJSON都为null。

我尝试过至少三种变化:

变化#1

 { "claimID" : "value", "rederenceDate" : "value" } 

变化#2:

 { "PlaceOrder" : { "claimID" : "value", "rederenceDate" : "value" } 

变化#3:

 { "ns0:PlaceOrder" : { "@xmlns:ns0" : "SQRT_WCF", "claimID" : "value", "rederenceDate" : "value" } 

我写了一个快速的C#控制台程序来构建和序列化一个对象,它匹配上面的Variation 1。 所以现在我认为问题不是JSON,而是SOAP-UI和Web服务之间的握手。 我将在旁边写一个C#测试客户端,看看那里发生了什么。

 SQRT_WCF.PlaceOrder order = new SQRT_WCF.PlaceOrder(); order.ClaimID = "claim1"; string strJson = new JavaScriptSerializer().Serialize(order); 

有人在webservice中询问了属性,假设这是他的意思:

public interface ISQRTREST {[OperationContract] void DoWork();

  [OperationContract] [WebInvoke(Method="GET", ResponseFormat = WebMessageFormat.Json , BodyStyle = WebMessageBodyStyle.Wrapped , UriTemplate ="json/{id}" )] string JSONData(String id); [OperationContract] [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "placeOrder/" )] SQ_jsonModel.Response placeOrder(PlaceOrder order); 

}

Web.Config中

                                         

更新:似乎更改BodyStyle = WebMessageBodyStyle.Bare使用变体1。

但现在,问题是我需要能够使用WebMessageBodyStyle.Wrapped。

这是它正在生产的现有Web服务。 编写该程序的人早已不复存在,现在B2B / BizTalk团队正在接管该项目。 我们正在使用尚未安装REST的BT2010,我们正在尝试为客户提供相同的界面,因此他们不必更改URL以外的任何内容。

RESTful Web服务正文格式似乎解释得相当好,我即将在C#中使用.wrapped选项尝试Variation 2。

更新2:使用BodyWrapped尝试变体2仍然获得一个null对象:

这是我包装它的方式。 在Update1中使用了什么

 string strPostBodyWrapped = "{\"PlaceOrder\" : " + strPostBody + "}"; 

午饭后会做更多的调试。

更新3:仍然没有运气。 基于上面的StackOverflow引用,看起来包装器应该是“实体”,我尝试了几种方法:

来自SOAP-UI:

 { "entity" : { "claimID" : "value", } 

我也试过“实体”而不是“实体”,只是确定。

我的DataContract中的所有字段都是字符串,因此应该没有问题序列化日期或数字。

来自C#Client测试程序:

  strPostBody = replaceSingleWithDoubleQuotes("{'ClaimID':'testvalue'}"); string strPostBodyWrapped = replaceSingleWithDoubleQuotes("{'entity': ") + strPostBody + "}"; public static string replaceSingleWithDoubleQuotes(string argText) { return argText.Replace("'", "\""); } 

如果我在SOAP_UI中尝试一些不好的东西,像这样:

 { "entity" : { xxx "claimID" : "value", } 

然后我意识到实体不是一个关键词,而是他class级的名字……哎呀。 所以我尝试了“Placeorder”和“placeorder”作为我案例的包装器。

我得到一个很好的错误:

 The server encountered an error processing the request. The exception message is 'The formatter threw an exception while trying to deserialize the message: Error in deserializing body of request message for operation 'placeOrderSQRT'. Encountered unexpected character 'x'.'... 

所以我不明白为什么在这种情况下解析器失败,但在其他情况下它不会失败,但它也不会设置任何字段值。

如果我尝试无效的字段名称,但语法正确,解析器似乎不会给出任何错误,例如“claimIDxxxxxxxx”:“value”

我想你可能需要对你的对象进行字符串化。

 var obj = { "claimID" : "value", "rederenceDate" : "value" } ....... data: '{ "argPlaceOrderJSON": ' + JSON.stringify(obj) + ' }' 

我有一个类似的问题,结果我必须定义我的请求格式和正文。 试试这个:

 [OperationContract] [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json)] YourResultType placeOrder(PlaceOrder argPlaceOrderJSON); 

答案被埋在这里:

WCF BodyStyle WrappedRequest对传入的JSON参数不起作用?

包装器的名称不是参数类型,而是参数名称。

所以在我的情况下,包装名称是“order”,因为我的parm名称是“order”:

 SQ_jsonModel.Response placeOrderSQRT(PlaceOrder order); 

以下是SOAP-UI的工作原理:

 { "order" : { "claimID" : "value", "rederenceDate" : "value" } 

对我而言,这非常令人震惊; 通常我们可以更改变量名称和参数名称(只是不是类名称),绝对不会影响用户界面。 参考文章显示了如何使用属性“MessageParameter”来设置外部名称,并且仍然允许在需要时更改内部名称。