views:

163

answers:

2

Hello,

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

+1  A: 
  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"&gt;
  <Achievement>
    <Name>Woke Up</Name>
  </Achievement>
  <Achievement>
    <Name>Went to work</Name>
  </Achievement>
  <Achievement>
    <Name>Slacked off</Name>
  </Achievement>
</Achievements>}
Andrew Anderson
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
`[XmlElement("Achievement")]` only sets the the child element of Achievements to "Achievement" -- it still leaves you with 3 levels of elements.
JoeGaggler
Andrew Anderson
A: 

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