4

I am trying to create a REST web service using .NET 4.0 and WCF. My REST service is returning a List which then gets serialized into XML. The problem I am having is that the XML being returned starts with ArrayOf, which I don't like.

In other words, right now the XML looks like this:

<ArrayOfAchievement>
    <Achievement>
        ...
    </Achievement>
</ArrayOfAchievement>

I would prefer to have the XML look like this:

<Achievements>
    <Achievement>
        ...
    </Achievement>
</Achievements>

If I create a new class and call it AchievementsList, which has a property of List< Achievement>, like so:

public class AchievementsList
{
    public List<Achievement> Achievements { get; set; }
}

Then have my service return the above class instead of List< Achievement>, the XML ends up looking like this:

<AchievementsList>
    <Achievements>
        <Achievement>
            ...
        </Achievement>
    </Achievements>
</AchievementsList>

Which is wrong (because it adds another level that doesn't belong there).

The other problem is that I also need to apply a namespace to the object, like so:

[XmlRoot(Namespace="NameSpaceURL")]
public class AchievementsList
{
    public List<Achievement> Achievements { get; set; }
}

Which I can't do if I just return a List< Achievement>.

So what can I do about these 2 problems?

Bara

Tunaki
  • 132,869
  • 46
  • 340
  • 423
Bara
  • 1,113
  • 6
  • 18
  • 28

3 Answers3

4
  1. You're on the right track with the AchievementList class, but what you need to do is decorate the Achievements list property with the XmlElement attribute, and supply the name of the individual elements.

  2. The namespace goes on the AchievementList class, just like you have it.

Sample code:

[Serializable]
public class Achievement {
    public string Name { get; set; }
}

[Serializable]
[XmlRoot(ElementName="Achievements", Namespace="http://www.mynamespace.com")]
public class AchievementList
{      
    [XmlElement("Achievement")]
    public List<Achievement> Achievements { get; set; }

    public AchievementList()
    {
        Achievements = new List<Achievement>();
    }

    public void Add(Achievement a)
    {
        Achievements.Add(a);
    }
}

And your output will be something like:

<?xml version="1.0" encoding="utf-16"?>
<Achievements xmlns="http://www.mynamespace.com">
  <Achievement>
    <Name>Woke Up</Name>
  </Achievement>
  <Achievement>
    <Name>Went to work</Name>
  </Achievement>
  <Achievement>
    <Name>Slacked off</Name>
  </Achievement>
</Achievements>}
Andrew Anderson
  • 3,409
  • 22
  • 25
  • When I add the ElementName attributes, nothing happens. Here's my code: http://screencast.com/t/MGJkY2MxY ... If I change it so that the element name is changed by the DataContract and DataMember, it does some odd things. Here's the code in that case: http://screencast.com/t/MGZkY2M0O ... And the result: http://screencast.com/t/OWYxYmRlZmQt – Bara Jun 22 '10 at 15:38
  • `[XmlElement("Achievement")]` only sets the the child element of Achievements to "Achievement" -- it still leaves you with 3 levels of elements. – JoeGaggler Jun 28 '10 at 23:36
  • I tested the code I posted before suggesting it, and the output is a copy & paste of what my tester console app spat out. Feel free to plug it into a test app of your own and let me know if you get different results. – Andrew Anderson Jun 29 '10 at 12:44
  • This didn't achieve the required result for me either. – Brad May 19 '16 at 08:08
1

I have a similar setup working like this: derive AchievementsList from List<Achievement>, decorate it with the XmlTypeAttribute and XmlRootAttribute, and also decorate Achievement with XmlTypeAttribute:

[XmlType(TypeName = "Achievements", Namespace="http://www.mynamespace.com")]
[XmlRoot(ElementName = "Achievements", Namespace="http://www.mynamespace.com")]
public class AchievementsList : List<Achievement>
{
}

[XmlType(TypeName = "Achievement", Namespace="http://www.mynamespace.com")]
public class Achievement
{
    ...
}

I also decorated my service implementation with the XmlSerializerFormat attribute so I can avoid the usual DataContract serialization.

JoeGaggler
  • 1,207
  • 1
  • 13
  • 28
1

I asked a related question on how to deserialize the XML produced by a WCF webservice method that returns List<SomeType>.

The XML has a root named <ArrayOfSomeType> and in order to deserialize that back into List<SomeType> one must use DataContractSerializer instead of XmlSerializer, since they are not compatible.

Community
  • 1
  • 1
angularsen
  • 8,160
  • 1
  • 69
  • 83