1

我是 WCF 的新手,并创建了一个简单的 REST 服务来接受一个订单对象(来自 XML 文件的一系列字符串),将该数据插入数据库,然后返回一个包含结果的订单对象。为了测试该服务,我创建了一个小型 Web 项目并通过从 xml 文档创建的流发送。

问题是,即使 xml 文档中的所有项目都放入了流中,服务在接收数据时也会取消其中的一些项目。例如 lineItemId 将有一个值,但发货状态将显示为 null。我逐步完成 xml 创建并验证是否正在发送所有值。但是,如果我清除数据成员并更改名称,它可以工作。任何帮助,将不胜感激。

这是接口代码

 [ServiceContract(Namespace="http://companyname.com/wms/")]
public interface IShipping
{

    [OperationContract]
    [WebInvoke(Method = "POST", UriTemplate = "/Orders/UpdateOrderStatus/", BodyStyle=WebMessageBodyStyle.Bare)]
    ReturnOrder UpdateOrderStatus(Order order);
}


[DataContract(Namespace="http://companyname.com/wms/order")]
public class Order
{
    [DataMember]
    public string lineItemId { get; set; }

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

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

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

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

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

[DataContract]
public class ReturnOrder
{
    [DataMember(Name = "Result")]
    public string Result { get; set; }

}

这是我用来发送 Order 对象的内容:

string lineId = txtLineItem.Text.Trim();
    string status = txtDeliveryStatus.Text.Trim();
    string TrackingNumber = "1x22-z4r32";
    string theMethod = "Ground";
    string carrier = "UPS";
    string ShipmentDate = "04/27/2010";

    XNamespace nsOrders = "http://tempuri.org/order";
    XElement myDoc =
        new XElement(nsOrders + "Order",
            new XElement(nsOrders + "lineItemId", lineId),
            new XElement(nsOrders + "shipmentStatus", status),
            new XElement(nsOrders + "trackingNumber", TrackingNumber),
            new XElement(nsOrders + "delvryMethod", theMethod),
            new XElement(nsOrders + "shipmentCarrier", carrier),
            new XElement(nsOrders + "shipmentDate", ShipmentDate)
    );

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:3587/Deposco.svc/wms/Orders/UpdateOrderStatus/");
    request.Method = "POST";
    request.ContentType = "application/xml";

    try
    {
        request.ContentLength = myDoc.ToString().Length;
        StreamWriter sw = new StreamWriter(request.GetRequestStream());
        sw.Write(myDoc);
        sw.Close();

        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {

            StreamReader reader = new StreamReader(response.GetResponseStream());
            string responseString = reader.ReadToEnd();

            XDocument.Parse(responseString).Save(@"c:\DeposcoSvcWCF.xml");
        }

    }
    catch (WebException wEx)
    {
        Stream errorStream = ((HttpWebResponse)wEx.Response).GetResponseStream();
        string errorMsg = new StreamReader(errorStream).ReadToEnd();
    }

来自 Web.Config 的绑定

<system.serviceModel>
    <services>
        <service behaviorConfiguration="DesposcoService.ShippingServiceBehavior" name="DesposcoService.ShippingService">
            <endpoint address="wms" binding="webHttpBinding" contract="DesposcoService.IShipping" behaviorConfiguration="REST" bindingNamespace="http://companyname.com/wms">
                <identity>
                    <dns value="localhost"/>
                </identity>
            </endpoint>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="DesposcoService.ShippingServiceBehavior">
                <!-- 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="REST">
                <webHttp/>
            </behavior>
        </endpointBehaviors>
    </behaviors>
</system.serviceModel>
4

1 回答 1

4

我发现了这一点(显然与詹姆斯差不多同时)。

问题在于DataContractSerializer,这里有一个重现它的测试用例:

class Program
{
    static void Main(string[] args)
    {
        XNamespace ns = "http://tempuri.org/";
        XElement element =
            new XElement(ns + "MyRequest",
                new XElement(ns + "ID", 5),
                new XElement(ns + "Name", "Test"),
                new XElement(ns + "Description", "This is a test"));

        DataContractSerializer serializer = new
            DataContractSerializer(typeof(MyRequest));
        using (XmlReader reader = element.CreateReader())
        {
            MyRequest request = (MyRequest)serializer.ReadObject(reader);
            Console.WriteLine("ID: {0}, Name: {1}, Description: {2}",
                request.ID, request.Name, request.Description);
        }
        Console.ReadLine();
    }

    [DataContract(Name = "MyRequest", Namespace = "http://tempuri.org/")]
    public class MyRequest
    {
        [DataMember]
        public int ID { get; set; }

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

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

如果您运行它,您会看到该Description属性为空。

发生这种情况是因为DataContractSerializer期望成员按字母顺序排列。当您同时使用DataContractSerializer客户端和服务时,这工作得很好......当您手动生成 XML 时不是很好。

如果将Order属性添加到DataMember属性,它会起作用:

    [DataContract(Name = "MyRequest", Namespace = "http://tempuri.org/")]
    public class MyRequest
    {
        [DataMember(Order = 0)]
        public int ID { get; set; }

        [DataMember(Order = 1)]
        public string Name { get; set; }

        [DataMember(Order = 2)]
        public string Description { get; set; }
    }

这次它找到了Description和所有其他字段。

因此,要解决此问题,您可以执行以下任一操作:

  • 向属性添加Order参数以DataMember匹配您实际计划生成 XML 的顺序;或者

  • 确保在客户端按字母顺序(按元素名称)添加元素。

我不是特别喜欢这两种解决方法。它们看起来很老套,很容易破解。我认为对于 POX 服务,我更喜欢使用 ,XmlSerializer而不是 ,DataContractSerializer因为它对这样的事情不那么挑剔,但它似乎并不完全适用于webHttpBinding. 有更多时间时值得研究的东西。

于 2010-04-29T13:44:31.317 回答