2010-04-29 4 views
1

Я новичок в WCF и создал простую службу REST для принятия объекта заказа (серия строк из файла XML), вставить эти данные в базу данных и затем вернуть объект заказа, который содержит результаты. Чтобы протестировать сервис, я создал небольшой веб-проект и передал поток, созданный из документа xml.Веб-служба WCF. Элементы данных по умолчанию

Проблема заключается в том, что даже если все элементы в 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; } 

} 

Это то, что я использую для отправки через объект заказа:

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

I понял это (очевидно, примерно в то же время, что и Джеймс).

Этот вопрос с 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. Что-то стоит исследовать, когда есть больше времени.

+0

У меня действительно есть пространства имен, определенные для контракта на обслуживание и контракта с данными. У них была информация о компаниях, поэтому я удалил их для публикации.После удаления их все, хотя, я получаю плохую просьбу 400 от сервера каждый трэйм, который я пытаюсь и подчиняю ему. – James

+0

@James: Можете ли вы включить эту информацию (анонимную в случае необходимости) в вопросе? Также опубликуйте, какие привязки/конфигурации вы используете - его трудно диагностировать без полного воспроизводимого случая. – Aaronaught

+0

Несомненно, как только я выясню, куда идти, чтобы отредактировать вопрос, я добавлю его (я новичок в переполнении стека) – James

Смежные вопросы