WCF Web服务数据成员默认为null [英] WCF web service Data Members defaulting to null

查看:92
本文介绍了WCF Web服务数据成员默认为null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am new to WCF and created a simple REST service to accept an order object (series of strings from XML file), insert that data into a database, and then return an order object that contains the results. To test the service I created a small web project and send over a stream created from an xml doc.

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

The problem is that even though all of the items in the xml doc get placed into the stream, the service is nullifying some of them when it receives the data. For example lineItemId will have a value but shipment status will show null. I step through the xml creation and verify that all the values are being sent. However, if I clear the datamembers and change the names around, it can work. Any help would be appreciated.

这是接口代码

 [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; }

}

这就是我用来发送订单对象:

This is what I'm using to send over an Order object:

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的绑定

Bindings from 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>


推荐答案

我发现了这一点(显然是在同一时间)

I figured this out (apparently at around the same time James did).

问题出在 DataContractSerializer ,下面是一个复制它的测试用例:

The issue is with the DataContractSerializer, and here is a test case that reproduces it:

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; }
    }
}

如果运行此命令,将会看到

If you run this, you'll see that it comes up empty for the Description property.

这是因为 DataContractSerializer code>期望成员按字母顺序排列。当您同时为客户端和服务使用 DataContractSerializer 时,此方法很好用...当您手动生成XML时,效果不是很好。

This happens because the DataContractSerializer expects members to be in alphabetical order. This works fine when you are using the DataContractSerializer for both the client and service... not so great when you're manually generating XML.

如果将 Order 属性添加到 DataMember 属性,则可以:

If you add Order properties to the DataMember attributes, it works:

    [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; }
    }

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

This time it finds the Description and all other fields.

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

So to resolve the issue, you can do either of the following:


  • DataMember 属性添加 Order 自变量以匹配顺序您实际上计划生成XML;或

  • Add Order arguments to the DataMember attributes to match the order in which you actually plan to generate XML; or

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

Make sure you add elements in alphabetical order (by element name) on the client side.

我并不特别喜欢这些解决方法。它们似乎很容易破解。我认为对于POX服务,我宁愿使用 XmlSerializer 而不是 DataContractSerializer ,因为它对诸如此类的东西不太挑剔那样,但是使用 webHttpBinding 似乎并不能立即使用。有更多时间值得研究。

I'm not particularly fond of either of these workarounds. They seem hackish and easy to break. I think for POX services I'd prefer to use the XmlSerializer instead of the DataContractSerializer since it's less finicky about things like that, but it doesn't quite seem to work out of the box with webHttpBinding. Something worth investigating when there's more time.

这篇关于WCF Web服务数据成员默认为null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆