views:

642

answers:

2

Hi guys.

I am having problem with using REST and returning response as an XML. I've created basic service from the template and everything looks nice but when I want to serialize my class and return it as a responce the service returns something else.

Take a look:

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

The first method is from the template, the second is mine. Returning structures look like this:

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

Edited:

When I am on the help page of the REST kit, I am getting this as a sample response for both methods which is wrong (I should not get this for the second method):

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

When I call first method like this:

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

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

I receive:

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"&gt;&lt;Value&gt;Sample DoWork response: 'bla bla'</Value></SampleResponseBody>

Whis is ok.

WHen I call second method like this:

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>

I am getting this:

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"/&gt;

And it should return a serialized to XML instance of class order_status What is wrong?

Thanks in advance.

After edit: ok, the problem was that for [OperationContract] XmlSerializer wasn't triggered. [XmlSerializerFormat] must be inserted right after the [OperationContract] to override default DataContractSerializer.

A: 

I would say that q_order_status should be decorated with [DataContract] attribute, and all of his members (along with those of order_status) should be decorated with [DataMember] attribute. Or did you omit these on purpose?

Can you try with this order_status code:

[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 note: I would also suggest that you follow .NET naming conventions for classes and members, PascalCase and no underscore. If you are restricted to a given xml name, you can use the Name member of the DataContract/DataMember attribute to define the xml name. (eg: [DataContract(Name="order_status")] public class OrderStatus). ;)

Philippe
@Philippe: *q_order_status* is passed as a parameter and it works fine. I need to return *order_status* in a deserialized XML. I am calling the service correctly via HTTP, but I will show you how..NET conventions: the problem is that I need to deserialize it to the exact XML structure which was not definied by me.
Wodzu
Can you try adding the [DataMember] attribute to all the members of the order_status class?
Philippe
Side note again: you can follow .NET naming convention and define the xml name of the element using the Name member of the DataContract/DataMember attribute: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractattribute.name.aspx
Philippe
I know, buf before I will start to mess with it. I want to obtain a basic result and it doesn't work.
Wodzu
From what I see, the response order_status contains no element. Can you try, as I said before, to add [DataMember] attributes to the order_status members (eddited the answer)?
Philippe
Philippe : it contains [DataContract] and is overrided by XMLSerializer :) I've found a solution but thanks for your help
Wodzu
+1  A: 

With the WCF REST Starter Kit, you should be able to create a method that returns an XElement as its return value:

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

In that case, your method implementation could look something like this:

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

This would return an XML fragment like this:

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

This way, anything really is possible - it's totally up to you how and what to create in terms of XML structure.

Marc

marc_s
marc_s: thanks, this is one of the ways to achieve this. But what if I would like to serialize some big object which contains other objects. In this solution I don't have serializer capabilities.. or am I wrong?
Wodzu
sure! You can have your `q_order_status` class and simply manually instantiate a XmlSerializer, and serialize an object of that type into a string and return it as a XElement. That should work just fine.
marc_s
Thanks for the tip. I will have to read more about the LINQ.
Wodzu