2

I am writing a Web API that clients can make requests to to return data in XML format. I am implementing this in .NET using Enterprise Foundation and MVC4.

I am struggling a bit with how to only return a subset of some fields from my Models in my Controllers.

For arguments sake, lets say I have a Product model that contains attributes "Id", "Name", "Price" and "Actual Cost" (I am using an example from http://www.asp.net/web-api/overview/creating-web-apis/using-web-api-with-entity-framework/using-web-api-with-entity-framework,-part-6)

I need to expose a Web API for clients to query a specific Product to get its name and price, but in this response I don't want to return the "Actual Cost" property (because this is our secret).

Now in the link I provide this is exactly the problem they are attempting to solve by the use of DTO's (they define a DTO called ProductDTO that contains only the subsets I want to return). I have implemented this solution and I am indeed now able to return only the fields I specify in the DTO.

The problem is that the naming used for the returned entity in XML is now ProductDTO rather than Product, i.e. the returned XML is

{"ProductDTO":[{"Id":1,"Name":"Tomato Soup","Price":1.39}, {"Id":3,"Name":"Yo yo","Price":6.99]}

rather than

{"Product":[{"Id":1,"Name":"Tomato Soup","Price":1.39}, {"Id":3,"Name":"Yo yo","Price":6.99]}

That means that all of our clients currently using our API and expects a "Product" to be returned will now get a "ProductDTO" returned, which means that they will have to make changes to their code and which is unacceptable. I need to provide them with a "Product" with only the relevant set of sub-fields as they are currently getting. How do I achieve this? I cannot simply "ignore" a data member as suggested in prevent property from being serialized in web api because I also have some API cases where I indeed DO need to return ALL the attributes and not only a subset.

Just some background: We have an existing API server interface that was written in Ruby on Rails and we are now moving this over to C# and .NET MVC4. We also have a bunch of client applications already interfacing to our existing, older, Ruby on Rails API Server and we don't want clients to make any changes to their code. We are simply moving our API server code over from Ruby on Rails to C#. In Ruby on Rails I was simply able to apply a filter to the XML Serializer when I need to only return a subset of attributes on certain calls.

Community
  • 1
  • 1
Stanley
  • 5,261
  • 9
  • 38
  • 55

2 Answers2

0

Suppose you have a class like

public class product
{
public string Name{get; set;}
..
}

and you don't want to appear it in the response you can just use [XMLIgnore] attribute

[XMLIgnore]
public string Name{get; set;}

hopes this helps.

Karthik Bammidi
  • 1,851
  • 9
  • 31
  • 65
  • 1
    You miss the part of the question where I mention that ignoring the attribute is not an option since there are cases where I DO need to use it. (The second link in my question actually shows similar suggestions.) Your suggestion would only work if I ALWAYS wanted to prevent the attribute from showing. Olav's answer describes what I wish to achieve. – Stanley Sep 20 '13 at 10:56
0

If you want to continue down the DTO route that you have started, which IMHO is a good idea as it gives you control of what you export without polluting your internal classes with export specific stuff, you can add a DataContract attribute to your ProductDTO class.

[DataContract(Name="Product")]
public class ProductDTO
{
    [DataMember]
    public int Id {get;set;}
    [DataMember]
    public string Name {get;set;}
}

The default XML formatter used in Web API is the DataContractSerializer. You can read more about this here

Olav Nybø
  • 11,454
  • 8
  • 42
  • 34
  • I would just also mention (although it is mentioned in the link you provide) that before each of the Properties you have to add [DataMember] if you are using DataContract since DataContract "makes serialization opt-in". Thanks for the help! – Stanley Sep 20 '13 at 10:53
  • You are right, I have updated the answer with DataMember attributes – Olav Nybø Sep 20 '13 at 11:17
  • Any idea how this would work when using an XMLSerializer rather than a DataContractSerializer? – Stanley Oct 08 '13 at 14:58
  • @Stanley XmlRoot attribute to control Element name. For complete list of attributes see this link: http://msdn.microsoft.com/en-us/library/83y7df3e.aspx – Olav Nybø Oct 08 '13 at 16:13
  • [XmlRoot(ElementName = "Product")] works fine when returning only one object in the xml. However, the moment I return a collection of products, it serializes it as "ArrayOfProductDTO" containing "ProductDTO" elements. – Stanley Oct 09 '13 at 05:29
  • No worries. I found the answer here: http://stackoverflow.com/questions/1440845/xmlroot-for-xml-serilization-does-not-work. If I use [XmlType("Product")] it works. – Stanley Oct 09 '13 at 05:33
  • I have posted a related question about the serialization of arrays here: http://stackoverflow.com/questions/19264826/how-to-serialize-a-collection-of-class-type-as-types-rather-than-arrayoftyp – Stanley Oct 09 '13 at 10:43