Reputation: 6989
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"><Value>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"/>
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
.
Upvotes: 1
Views: 4893
Reputation: 580
This question (and the last edit) helped us to solve a similar problem. Instead of decorating thousands of data elements with DataContract/DataMember attributes and using the (default) DataContractSerializer, we found that if our WCF service used the XmlSerializerFormat instead, we could easily deserialize our objects.
For those who need an example:
[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);
}
This is how we're deserializing the objects:
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;
}
Upvotes: 0
Reputation: 755216
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
Upvotes: 4
Reputation: 4051
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). ;)
Upvotes: 0