How to serialize xml into desired format in asp.net web api

12,228

Solution 1

Is there any reason why you are using the XmlSerializer over the DataContract serialiszer?

If not you can achieve what you want like so:

  1. Remove config.Formatters.XmlFormatter.UseXmlSerializer = true; from your config
  2. Add a reference to System.Runtime.Serialisation
  3. Declare your class and controller

Code

[DataContract(Namespace = "")]
public class Quiz
{
    [DataMember]
    public int QuizId { get; set; }
    [DataMember(Name = "title")]
    public string Title { get; set; }
}

[CollectionDataContract(Name = "Quizs", Namespace = "")]
public class QuizCollection : List<Quiz>
{
}

public class QuizsController : ApiController
{
    public QuizCollection Get()
    {
        return new QuizCollection
                       {
                           new Quiz {QuizId = 4, Title = "Master Minds"},
                           new Quiz {QuizId = 5, Title = "Another Title"}
                       };
    }
}

Finally call your service using the html header "accept : application/xml"

And your result should be like:

<Quizs xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <Quiz>
        <QuizId>4</QuizId>
        <title>Master Minds</title>
        </Quiz>
    <Quiz>
        <QuizId>5</QuizId>
        <title>Another Title</title>
    </Quiz>
</Quizs>

Regarding your namespaces NB. how they are set to namespace = "" in attributes to remove them. You are going to strugle to remove xmlns:i="http://www.w3.org/2001/XMLSchema-instance" it needs to be there to allow the XML to handle null values.

For more information on the datacontract serializers support for collections see here

Solution 2

You can remove the namespace. Just create a CustomXmlFormatter to remove the namespace from the root element.

public class IgnoreNamespacesXmlMediaTypeFormatter : XmlMediaTypeFormatter
{
public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
{
    try
    {
        var task = Task.Factory.StartNew(() =>
        {
            var xns = new XmlSerializerNamespaces();
            var serializer = new XmlSerializer(type);
            xns.Add(string.Empty, string.Empty);
            serializer.Serialize(writeStream, value, xns);
        });

        return task;
    }
    catch (Exception)
    {
        return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
    }
}
}

Solution 3

Create a class called QuizList and implement IXmlSerializable and you can define exactly how you want your XML to look.

IMHO it is a really bad idea to expose wire formats that are dependent on the internal implementations of a .Net type serializer. The whole idea of serializers is that when you want to deserialize the object you need to have the same serializer library and the same types available to reconstitute the object. What happens if your client isn't on the .net platform?

Share:
12,228

Related videos on Youtube

Karthik Bammidi
Author by

Karthik Bammidi

Updated on September 15, 2022

Comments

  • Karthik Bammidi
    Karthik Bammidi about 1 year

    I am working on asp.net mvc 4 web api. I have a class like,

    public class Quiz
    {
    public int QuizId{get; set;}
    public string title{get; set;}
    ...
    ...
    }
    

    and now i am trying to retrieve list of quizs so i wrote like,

    public List<Quiz> GetQuizs()
    {
    return repository.ListQuizs();
    }
    

    i need xml response so i have made configuration in webapi.config file like,

    config.Formatters.XmlFormatter.UseXmlSerializer = true;
    

    and i got a response like,

    <ArrayOfQuiz xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Quiz>
    <QuizId>4</QuizId>
    <title>Master Minds</title>
    </Quiz>
    <Quiz>
    <QuizId>5</QuizId>
    <title>Master Minds</title>
    </Quiz>
    </ArrayOfQuiz>
    

    but i want the response like

    <Quizs>
    <Quiz>
    <QuizId>4</QuizId>
    <title>Master Minds</title>
    </Quiz>
    <Quiz>
    <QuizId>5</QuizId>
    <title>Master Minds</title>
    </Quiz>
    </Quiz>
    

    i have tried like,

    public class quizs:List<Quiz>{}
    public class Quiz
    {
    //properties here
    }
    

    but i am unable to load list of quizs into quizs class. please guide me.

  • Aliostad
    Aliostad almost 11 years
    When you have control over the class, implementing IXmlSerializable is overkill.
  • Darrel Miller
    Darrel Miller almost 11 years
    @Aliostad Wire formats should either be completely under your control or be defined by an open spec. Being dependent on a vendor's private implementation is a recipe for future pain.
  • Aliostad
    Aliostad almost 11 years
    @DarrelMiller not really talking about the format. That is handled by media type formatter. We are talking about domain implementation.
  • Darrel Miller
    Darrel Miller almost 11 years
    @Aliostad IMO Web API Controller signatures are not a domain concern and domain objects certainly shouldn't be transferred over the wire.
  • Aliostad
    Aliostad almost 11 years
    @DarrelMiller well again I am talking about server's Public domain and domain object as in CSDS. Obviously a mapper will translate private domain to domain object (also commonly referred to as viewmodel).