如何在 WCF Rest 服务中创建 JSON 到 match/serialize 到 DataContract

How to create JSON to match/serialize to DataContract in WCF Rest Service

接口:

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)
{
   ...
}

我已将我的网络服务附加到工作进程,并通过代码进行跟踪。到目前为止,我所尝试的一切,变量 argPlaceOrderJSON 都是空的。

我至少尝试了三种变体:

变体 #1

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

变化 #2:

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

变化 #3:

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

我编写了一个快速的 C# 控制台程序来构建和序列化一个对象,它与上面的变体 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 接口 ISQRTREST { [操作合约] 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

<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="SQRT_WCF.SQRTREST" behaviorConfiguration="ServiceBehaviour">
        <endpoint address="" binding="webHttpBinding" bindingConfiguration="longTimeoutBinding" contract="SQRT_WCF.ISQRTREST" behaviorConfiguration="web">
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehaviour">
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <bindings>
      <webHttpBinding>
        <binding name="longTimeoutBinding"
        receiveTimeout="00:10:00" sendTimeout="00:10:00">
          <security mode="None"/>
        </binding>
      </webHttpBinding>
    </bindings>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

</configuration>

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

但是现在,问题是我需要能够让它与 WebMessageBodyStyle.Wrapped 一起工作。

这是生产中的现有 Web 服务。写程序的人早就不在了,现在B2B/BizTalk团队接手了这个项目。我们正在使用还没有 REST 的 BT2010,并且我们正在尝试为我们的客户提供相同的界面,因此他们无需更改 URL 以外的任何内容。

RESTful web service body format 似乎解释得相当好,我将尝试使用 C# 中的 .wrapped 选项进行变体 2。

更新 2: 尝试使用 BodyWrapped 的变体 2 仍然得到一个空对象:

我就是这样包装的。采用在 Update1 中有效的方法

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

午餐后将进行更多调试。

更新 3: 仍然没有运气。根据上面的 Whosebug 参考,包装器看起来应该是 "entity",我尝试了几种方法:

来自 SOAP-UI:

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

我也试过 "Entity" 而不是 "entity",请确定。

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

来自 C# 客户端测试程序:

            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 doesn't work for incoming JSON param?

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

所以在我的例子中,包装器名称是 "order",因为我的参数名称是 "order":

SQ_jsonModel.Response placeOrderSQRT(PlaceOrder order);

以下来自 SOAP-UI 现在的作品:

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

对我来说这是非常震惊的;通常我们可以更改变量名称和参数名称(只是不是 Class 名称),而对用户界面绝对没有影响。参考文献 post 展示了如何使用属性 "MessageParameter" 来设置外部名称,并且仍然允许在需要时更改内部名称。