1

I have a .NET Web API project where I have a Data Transfer Object Class which I want to serialize to XML.

The class (simplified) is basically defined as follows:

[XmlType("user")]
public class PublicVisibleUserDTO
{   
    public long id { get; set; }
    public string screenname { get; set; }
}

Now, when I call a function that returns only one element, I get good and proper XML as I expect:

<user>
    <id>123</id>
    <screenname>john</screenname>
</user>

However, when I have a function that returns a collection of this Data Transfer Object I get:

<ArrayOfUser>
    <user>
        <id>123</id>
        <screenname>john</screenname>
    </user>
    <user>
        <id>124</id>
        <screenname>jane</screenname>
    </user>
</ArrayOfUser>

But what I want is:

<users>
    <user>
        <id>123</id>
        <screenname>john</screenname>
    </user>
    <user>
        <id>124</id>
        <screenname>jane</screenname>
    </user>
</users>

So basically I want the collection to be returned as "types" (users) rather than "ArrayOfType" (ArrayOfUser). How do I do this?

I have tried applying an XmlArray/XmlArrayAttribute function at the top of the class declaration, but that cannot be applied to a class definition.

Stanley
  • 5,261
  • 9
  • 38
  • 55
  • Try by adding the XmlArrayAttribute to the attributes of your list, there you can give it a name as follows: [System.Xml.Serilaization.XmlArray("users")] List users; – MakePeaceGreatAgain Oct 09 '13 at 06:44
  • What list? You will notice that I don't have a "list" or "collection" as one of the attributes in my class that I want to serialize. I want to set the class itself so that when it gets serialized "automagically" by the .NET Web API framework it is serialized as "users" rather than as "ArrayOfUser". – Stanley Oct 09 '13 at 06:47
  • How is your collection defined then that serializes to ArrayOfUsers – MakePeaceGreatAgain Oct 09 '13 at 06:48
  • In controller actions that return a collection of the class, I return a collection of type IEnumerable which gets populated via Linq queries in Entity Framework. This happens, for example, when requesting a REST URL of sorts "GET /api/users" as per REST Web API convention. – Stanley Oct 09 '13 at 06:52
  • I guess a solution would be to have a class inheriting from IEnumerable, put the correct serialization attributes on it, and return it as result of your methods, through a converter. – jbl Oct 09 '13 at 07:55
  • No that would not be right. The class represents a Model in the Web API (and EF). In a Web API some of the common URL's and methods are "GET /api/users/1" which returns a single user and "GET /api/users" which returns a collection of users. The methods for these are defined in a Controller. So the Controller returns either a single instance or a collection of items of Model type, based on the request. It would be incorrect to let the Model inherit from IEnumerable as it is not a sub-type of IEnumerable. If I do that, "GET /api/users" would return an array of IEnumberables, which is incorrect. – Stanley Oct 09 '13 at 08:12
  • 1
    seems to be the solution provided here : http://stackoverflow.com/a/13057393/1236044 – jbl Oct 09 '13 at 13:04

1 Answers1

2

I have found a workaround based on jbl's link provided. (I call it a workaround rather than a solution as I cannot believe that there isn't a simpler way to achieve this, but at least this gets the job done for now).

I added an extra class that inherits from List as the link suggests:

[XmlRoot("users")]
public class PublicVisibleUsersList : List<PublicVisibleUserDTO> { }

Now, by default, when performing a Linq query in a controller action that returns more than one element, I would get some kind of IEnumberable back. So my existing controller action would look something like:

    // GET api/users
    public IEnumerable<PublicVisibleUserDTO> Getusers()
    {
        var results = dbContext.Users.Where...//Entity Framework Linq query to fill data from database
        return results;
    }

but I modified this to return a value of the new collection type:

    // GET api/users
    public PublicVisibleUsersList Getusers()
    {
        PublicVisibleUsersList myList = new PublicVisibleUsersList();
        var results = dbContext.Users.Where...//Entity Framework Linq query to fill data from database
        myList.AddRange(results); //AddRange() accepts an IEnumerable<T>, so I'm able to "convert" my results from the linq query to my newly defined list type by adding the result values to myList           
        return myList;
    }
Community
  • 1
  • 1
Stanley
  • 5,261
  • 9
  • 38
  • 55
  • I'm using the default serializer (DataContract) so instead of using XmlRoot I had to use this attribute on the PublicVisibleUsersList class: CollectionDatacontract. Also you can add a constructor to your list class that takes the IEnumerable, that way you don't have to do the AddRange stuff. – Haukman Apr 09 '15 at 18:18
  • Thanks dear it works for me. after wasting many hours i got this answer as clear what to do.. good work – UsmanMirza Nov 12 '17 at 09:44