2009-09-30 2 views
1

У меня возникла проблема с использованием REST и возвращаемого ответа в виде XML. Я создал базовый сервис из шаблона, и все выглядит хорошо, но когда я хочу сериализовать свой класс и вернуть его в качестве ответа, служба возвращает что-то еще.Сериализация в XML с использованием REST и WCF

Посмотрите:

[WebHelp(Comment = "Sample description for DoWork")] 
[WebInvoke(UriTemplate = "DoWork")] 
[OperationContract] 
public SampleResponseBody DoWork(SampleRequestBody request) 
{ 
    //TODO: Change the sample implementation here 
    return new SampleResponseBody() 
    { 
     Value = String.Format("Sample DoWork response: '{0}'", request.Data) 

    }; 
} 

[WebHelp(Comment = "Returns order state based on client and order number")] 
[WebInvoke(UriTemplate = "OrderStatus")] 
[OperationContract] 
public order_status OrderStatus(q_order_status request) 
{ 
    return new order_status() 
    { 
     error_id = 0, 
     client_acr = "client", 
     order_acr = "order" 
    }; 
} 

Первый метод из шаблона, второй мой. Повторные структуры выглядеть следующим образом:

public class SampleResponseBody 
{ 
    [DataMember] 
    public string Value { get; set; } 
} 

public class q_order_status 
{ 
    public string client_acr; 
    public string order_acr; 
} 

[DataContract] 
[XmlSerializerFormat] 
public class order_status 
{ 
    [XmlAttribute] 
    public int error_id; 
    [XmlElement] 
    public string error_desc; 
    [XmlElement] 
    public string order_acr; 
    [XmlElement] 
    public string client_acr; 
} 

Отредактировано:

Когда я нахожусь на странице помощи комплекта REST, я получаю это как ответ образца для обоих методов что является неправильным (Я не должен получить это для второго способа):

<SampleResponseBody> 
<Value>String content</Value> 
</SampleResponseBody> 

Когда я называю первый метод, как это:

User-Agent: Fiddler 
Host: ipv4.fiddler:4617 
Content-Type: text/xml 
Content-Length: 63 

<SampleRequestBody> 
<Data>bla bla</Data> 
</SampleRequestBody> 

я получаю:

HTTP/1.1 200 OK 
Server: ASP.NET Development Server/9.0.0.0 
Date: Wed, 30 Sep 2009 09:41:20 GMT 
X-AspNet-Version: 2.0.50727 
Cache-Control: private 
Content-Type: application/xml; charset=utf-8 
Content-Length: 141 
Connection: Close 

<SampleResponseBody xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Value>Sample DoWork response: 'bla bla'</Value></SampleResponseBody> 

Whis нормально.

Когда я называю второй метод, как это:

User-Agent: Fiddler 
Host: ipv4.fiddler:4617 
Content-Type: text/xml 
Content-Length: 115 

<q_order_status> 
<client_acr>String content</client_acr> 
<order_acr>String content</order_acr> 
</q_order_status> 

Я получаю это:

HTTP/1.1 200 OK 
Server: ASP.NET Development Server/9.0.0.0 
Date: Wed, 30 Sep 2009 09:44:18 GMT 
X-AspNet-Version: 2.0.50727 
Cache-Control: private 
Content-Type: application/xml; charset=utf-8 
Content-Length: 67 
Connection: Close 

<order_status xmlns:i="http://www.w3.org/2001/XMLSchema-instance"/> 

И он должен вернуть сериализованная в XML экземпляр класса order_status Что не так?

Заранее спасибо.

После редактирования: ОК, проблема в том, что для [OperationContract]XmlSerializer не был запущен. [XmlSerializerFormat] необходимо установить сразу после [OperationContract] , чтобы переустановить значение по умолчанию DataContractSerializer.

ответ

4

С WCF REST Starter Kit, вы должны быть в состоянии создать метод, который возвращает XElement как возвращаемого значения:

[WebHelp(Comment = "Returns order state based on client and order number")] 
[WebInvoke(UriTemplate = "OrderStatus")] 
[OperationContract] 
public XElement OrderStatus(q_order_status request) 
{ 
    ..... 
} 

В этом случае, ваша реализация метода может выглядеть примерно так:

public XElement OrderStatus(q_order_status request) 
{ 
    return new XElement("q_order_status", 
       new XAttribute("error_id", 0), 
       new XElement("client_acr", "client acr value"), 
       new XElement("order_acr", "order acr value") 
      ); 
} 

Это возвращает фрагмент XML, как это:

<q_order_status error_id="0"> 
    <client_acr>client acr value</client_acr> 
    <order_acr>order acr value</order_acr> 
</q_order_status> 

Таким образом, все возможно - все зависит от вас, как и что создавать с точки зрения структуры XML.

Марк

+0

marc_s: спасибо, это один из способов достижения этого. Но что делать, если я хотел бы сериализовать большой объект, содержащий другие объекты. В этом решении у меня нет возможностей сериализатора .. или я не прав? – Wodzu

+0

уверен! Вы можете иметь свой класс 'q_order_status' и просто вручную создавать экземпляр XmlSerializer и сериализовать объект этого типа в строку и возвращать его как XElement. Это должно работать нормально. –

+0

Спасибо за подсказку. Мне нужно больше узнать о LINQ. – Wodzu

0

Я бы сказал, что q_order_status должен быть украшен атрибутом [DataContract], и все его члены (вместе с атрибутами order_status) должны быть украшены атрибутом [DataMember]. Или вы опускаете их специально?

Вы можете попробовать с этим order_status кодом:

[DataContract] 
public class order_status 
{ 
    [DataMember] 
    public int error_id; 
    [DataMember] 
    public string error_desc; 
    [DataMember] 
    public string order_acr; 
    [DataMember] 
    public string client_acr; 
} 

Side Примечания: Я хотел бы также предположить, что вы будете следовать соглашениям об именовании .NET для классов и членов, PascalCase и не подчеркивания. Если вы ограничены заданным именем xml, вы можете использовать элемент Name атрибута DataContract/DataMember, чтобы определить имя xml. (например: [DataContract (Name = "order_status")] public class OrderStatus).;)

+0

@Philippe: * q_order_status * передается в качестве параметра, и она отлично работает. Мне нужно вернуть * order_status * в десериализованном XML. Я правильно звоню в службу через HTTP, но я покажу вам, как это сделать. .NET-соглашения: проблема в том, что мне нужно десериализовать его до точной структуры XML, которая не была определена мной. – Wodzu

+0

Можете ли вы попробовать добавить атрибут [DataMember] ко всем членам класса order_status? – Philippe

+0

Еще раз обратите внимание: вы можете выполнить соглашение об именах .NET и определить имя xml элемента, используя элемент Name атрибута DataContract/DataMember: http://msdn.microsoft.com/en-us/library/system.runtime .serialization.datacontractattribute.name.aspx – Philippe

0

Этот вопрос (и последняя правка) помогли нам решить подобную проблему. Вместо того, чтобы украшать тысячи элементов данных атрибутами DataContract/DataMember и использовать (по умолчанию) DataContractSerializer, мы обнаружили, что если наша служба WCF использовала XmlSerializerFormat, мы могли бы легко десериализовать наши объекты.

Для тех, кто нужен пример:

[System.ServiceModel.ServiceContract] 
public interface IRestService 
{ 
    [System.ServiceModel.OperationContract] 
    // Added this attribute to use XmlSerializer instead of DataContractSerializer 
    [System.ServiceModel.XmlSerializerFormat(
     Style=System.ServiceModel.OperationFormatStyle.Document)] 
    [System.ServiceModel.Web.WebGet(
     ResponseFormat = System.ServiceModel.Web.WebMessageFormat.Xml, 
     UriTemplate = "xml/objects/{myObjectIdentifier}")] 
    MyObject GetMyObject(int myObjectIdentifier); 
} 

Это, как мы десериализации объектов:

public static T DeserializeTypedObjectFromXmlString<T>(string input) 
{ 
    T result; 

    try 
    { 
     System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(T)); 
     using (System.IO.TextReader textReader = new System.IO.StringReader(input)) 
     { 
      result = (T)xs.Deserialize(textReader); 
     } 
    } 
    catch 
    { 
     throw; 
    } 

    return result; 
} 
+0

Я рад, что это помогло вам! – Wodzu

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