如何将DataContract对象作为WCF RESTFUL Web服务的参数发送?

时间:2013-09-06 07:06:41

标签: json wcf rest wcf-rest

我正在开发一个WCF resful服务,它基本上会从某些移动应用程序中消耗掉。 在POST上我试图发送一个DataContract对象[实际上我必须发送一个对象列表]和另一个单独的id作为字符串。我的问题是,是否可能定义我的函数来接受DataContract对象和单个字符串?

以下是我的代码: 接口声明:

[ServiceContract]
    public interface IService1
    {

        [OperationContract]
        [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "GetDataUsingDataContract/{id}")]
        CompositeType GetDataUsingDataContract(string id, CompositeType composite );


    }

    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }

该功能的实际定义:

public CompositeType GetDataUsingDataContract(string id, CompositeType composite )
        {

            if (composite == null)
            {
                throw new ArgumentNullException("composite");
            }
            if (composite .BoolValue)
            {
                composite .StringValue += "- Suffix and the id is"+id;
            }
            return report;
        }

我试图从Fiddler发送的json对象是

{"BoolValue":true,"StringValue":"sdfsdfsf"}

Fiddler snap when sending the request Fiddler snap of the output 以上是我正在测试服务的小提琴手的快照。 经过几次谷歌搜索后,我得到了以下链接,其中客户端实际使用webservice引用获取DataContract类型并序列化为json,然后作为请求体发送。但是为什么我对Fiddler的测试没有成功? http://dotnetmentors.com/wcf/wcf-rest-service-to-get-or-post-json-data-and-retrieve-json-data-with-datacontract.aspx

任何人都可以提出任何建议吗?

web.config如下:

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

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="JSONWebService.Service1" behaviorConfiguration="JSONWebService.Service1Behavior">
        <endpoint address="../Service1.svc"
            binding="webHttpBinding"
            contract="JSONWebService.IService1"
            behaviorConfiguration="webBehaviour" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="JSONWebService.Service1Behavior">

          <!-- 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="true"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="webBehaviour">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

</configuration>

1 个答案:

答案 0 :(得分:12)

要使这种情况发挥作用,您需要做几件事。

首先,在服务合同中,您需要标记具有多个参数的方法,并将 WebInvoke 属性的 BodyStyle 参数设置为 Wrapped 如本示例所示(根据您链接到http://dotnetmentors.com/wcf/wcf-rest-service-to-get-or-post-json-data-and-retrieve-json-data-with-datacontract.aspx的示例改编):

[OperationContract]
[WebInvoke(UriTemplate = "/PlaceOrder",
    RequestFormat = WebMessageFormat.Json,
    ResponseFormat = WebMessageFormat.Json, Method = "POST",
    BodyStyle = WebMessageBodyStyle.Wrapped)]
bool PlaceOrder(string id, OrderContract order);

使用此属性参数,您必须将多个Web方法参数包装到客户端的单个字符串中。以下示例显示了在C#中执行此操作的方法:

  var requestdata = new
  {
    id = order.OrderID,
    order = order
  };
  string data2 = JsonConvert.SerializeObject(requestdata);

请注意,匿名方法中的字段名称与Web方法中的参数名称匹配。

作为参考,此处生成的JSON如下所示,您可以在JSON字符串中看到 id order 对象:

{"id":"10560","order":{"OrderID":"10560","OrderDate":"06/09/2013 12:29:04","ShippedDate":"16/09/2013 12:29:04","ShipCountry":"Uganda","OrderTotal":"781"}}

你应该能够用你的例子在Fiddler中以这种格式测试JSON。


扩展答案以处理其他数据类型

使用包含 bool DateTime 属性的 DataContract

[DataContract]
public class OrderContract
{
  [DataMember]
  public string OrderID { get; set; }

  [DataMember]
  public string OrderDate { get; set; }

  [DataMember]
  public string ShippedDate { get; set; }

  [DataMember]
  public string ShipCountry { get; set; }

  [DataMember]
  public string OrderTotal { get; set; }

  [DataMember]
  public bool Shipped { get; set; }

  [DataMember]
  public DateTime DeliveredDate { get; set; }
}

此处的问题是处理 DateTime 并确保JSON采用WCF RESTful服务可以反序列化的格式。为了实现这一点,我在客户端上使用了这段代码:

OrderContract order = new OrderContract
{
  OrderID = "10560",
  OrderDate = DateTime.Now.ToString(),
  ShippedDate = DateTime.Now.AddDays(10).ToString(),
  ShipCountry = "India",
  OrderTotal = "781",
  Shipped = true,
  DeliveredDate = DateTime.Now
};

DataContractJsonSerializer ser =
        new DataContractJsonSerializer(typeof(OrderContract));
MemoryStream mem = new MemoryStream();
ser.WriteObject(mem, order);
string data =
    Encoding.UTF8.GetString(mem.ToArray(), 0, (int)mem.Length);

var requestdata = new
{
  id = order.OrderID,
  order = order
};
JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
{
  DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
};
string data2 = JsonConvert.SerializeObject(requestdata, microsoftDateFormatSettings);
WebClient webClient = new WebClient();
webClient.Headers["Content-type"] = "application/json";
webClient.Encoding = Encoding.UTF8;
webClient.UploadString("http://localhost:61966/OrderService.svc/PlaceOrder", "POST", data2);

请注意JSON Serializer设置 - 这会生成以下JSON:

{"id":"10560","order":{"OrderID":"10560","OrderDate":"10/09/2013 16:15:30","ShippedDate":"20/09/2013 16:15:30","ShipCountry":"India","OrderTotal":"781","Shipped":true,"DeliveredDate":"\/Date(1378826130655+0100)\/"}}