Tuesday, June 23, 2015

MVC Web API – Customizing root element name in resultant XML


Problem:
Whenever we try to return list of an object from API we get an xml response where root element is ArrayOfYourObjectName that we like to be some plural form of our object name e.g. if our object name is Student then generated xml’s root element’s name should be  Students instead of ArrayOfStudent.    

Emulating the problem:

We will first create a table for purpose of illustration as follows
CREATE TABLE [dbo].[MyTable] (
    [Id]     INT           IDENTITY (1, 1) NOT NULL,
    [Name]   VARCHAR (100) NOT NULL,
    [Email]  VARCHAR (100) NOT NULL,
    [Gender] CHAR (1)      NULL,
    [Phone]  VARCHAR (20)  NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);
Add some dummy entries in table.
Now into our MVC web API project add a new class file and create a class as follows
    public class Employee
    {
        private string _gender;

        [Display(Name = "Employee Id")]
        public int Id{get;set;}

        [Display(Name = "Name")]
        [Required]
        [StringLength(100)]
        public string Name{get;set;}

        [Display(Name = "Email")]
        [Required]
        [StringLength(100)]
        public string Email{get;set;}

        [StringLength(20)]
        public string Phone{get;set;}

        public string Gender{
            get
            {
                return _gender;
            }
            set
            {
                switch (value)
                {
                    case "M":
                        _gender = "Male";
                        break;
                    case "F":
                        _gender = "Female";
                        break;
                    default:
                        _gender = "Not Disclosed";
                        break;
                }
            }
        }
    }

    public class Employees : List<Employee>
    {
    }
Now add Entity model with name say MyDatabaseEntities

go to Value Controller which usually created by default and edit get method to resemble below
public Employees Get()
        {
            List<Employee> d =(from m in new MyDatabaseEntities().MyTables
                                select new Employee() { Id = m.Id, Name = m.Name, Email = m.Email, Phone = m.Phone, Gender = m.Gender }).ToList<Employee>();

            Employees dd = new Employees();
            dd.AddRange(d);
            return dd;
        }
Now run the application and visit api/values result will be like
<ArrayOfEmployee xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/MvcApplication1.Models">
<Employee>
<Email>surendra@gmail.com</Email>
<Gender>Male</Gender>
<Id>3</Id>
<Name>surendra</Name>
<Phone>9890968645</Phone>
</Employee>
<Employee>
<Email>rajendra@gmail.com</Email>
<Gender>Male</Gender>
<Id>4</Id>
<Name>rajendra</Name>
<Phone>9890964645</Phone>
</Employee>
<Employee>
<Email>sunidhi@gmail.com</Email>
<Gender>Female</Gender>
<Id>5</Id>
<Name>sunidhi</Name>
<Phone>9890564645</Phone>
</Employee>
<Employee>
<Email>nidhi@gmail.com</Email>
<Gender>Female</Gender>
<Id>6</Id>
<Name>nidhi</Name>
<Phone>9880564645</Phone>
</Employee>
<Employee>
<Email>shirin@gmail.com</Email>
<Gender>Female</Gender>
<Id>7</Id>
<Name>shirin</Name>
<Phone>9880464645</Phone>
</Employee>
<Employee>
<Email>nilima@gmail.com</Email>
<Gender>Female</Gender>
<Id>8</Id>
<Name>nilima</Name>
<Phone>9680464645</Phone>
</Employee>
</ArrayOfEmployee>

The XML response we got has root element ArrayOfEmployee which might be undesired behavior.
You will get similar response on below variant of our api action
public LIST<Employee> Get()
        {
            List<Employee> d =(from m in new MyDatabaseEntities().MyTables
                                select new Employee() { Id = m.Id, Name = m.Name, Email = m.Email, Phone = m.Phone, Gender = m.Gender }).ToList<Employee>();

            return d;
        }


Objective:
Our aim is to replace ArrayOfEmployee root element name by more suitable name say Employees.

Solution:
    MVC uses DataContractSerializer  for serializing data since version 4.0 and for earlier version XmlSerializer .
 If using MVC 4.0 or latter change employees class as
[CollectionDataContract(Name = " Employees", ItemName = " Employee")]
    public class Employees : List<Employee>
    {
    }
Now visit api/values it will call our get action and result will be
<Employees xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/MvcApplication1.Models">
<Employee>
<Email>jitendra@gmail.com</Email>
<Gender>Male</Gender>
<Id>2</Id>
<Name>jitendra</Name>
<Phone>9890868645</Phone>
</Employee>
<Employee>
<Email>surendra@gmail.com</Email>
<Gender>Male</Gender>
<Id>3</Id>
<Name>surendra</Name>
<Phone>9890968645</Phone>
</Employee>
<Employee>
<Email>rajendra@gmail.com</Email>
<Gender>Male</Gender>
<Id>4</Id>
<Name>rajendra</Name>
<Phone>9890964645</Phone>
</Employee>
<Employee>
<Email>sunidhi@gmail.com</Email>
<Gender>Female</Gender>
<Id>5</Id>
<Name>sunidhi</Name>
<Phone>9890564645</Phone>
</Employee>
<Employee>
<Email>nidhi@gmail.com</Email>
<Gender>Female</Gender>
<Id>6</Id>
<Name>nidhi</Name>
<Phone>9880564645</Phone>
</Employee>
<Employee>
<Email>shirin@gmail.com</Email>
<Gender>Female</Gender>
<Id>7</Id>
<Name>shirin</Name>
<Phone>9880464645</Phone>
</Employee>
<Employee>
<Email>nilima@gmail.com</Email>
<Gender>Female</Gender>
<Id>8</Id>
<Name>nilima</Name>
<Phone>9680464645</Phone>
</Employee>
</Employees>

If MVC version is less than 4.0 then go to configuration (WebAPiConfig.cs) and add line
config.Formatters.XmlFormatter.UseXmlSerializer = true;
which means xml serialization is done using legacy xml Serializer

change our employees class as
[XmlRoot("Employees")]
    //[CollectionDataContract(Name = "Employees", ItemName = "Employee")]
    public class Employees : List<Employee>
    {
    }
This will set root element name to “Employees” whenever object of this class is serialized into xml.
Now visit /Api/Values resultant xml will be
<Employees xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Employee>
<Id>3</Id>
<Name>surendra</Name>
<Email>surendra@gmail.com</Email>
<Phone>9890968645</Phone>
<Gender>Male</Gender>
</Employee>
<Employee>
<Id>4</Id>
<Name>rajendra</Name>
<Email>rajendra@gmail.com</Email>
<Phone>9890964645</Phone>
<Gender>Male</Gender>
</Employee>
<Employee>
<Id>5</Id>
<Name>sunidhi</Name>
<Email>sunidhi@gmail.com</Email>
<Phone>9890564645</Phone>
<Gender>Female</Gender>
</Employee>
<Employee>
<Id>6</Id>
<Name>nidhi</Name>
<Email>nidhi@gmail.com</Email>
<Phone>9880564645</Phone>
<Gender>Female</Gender>
</Employee>
<Employee>
<Id>7</Id>
<Name>shirin</Name>
<Email>shirin@gmail.com</Email>
<Phone>9880464645</Phone>
<Gender>Female</Gender>
</Employee>
<Employee>
<Id>8</Id>
<Name>nilima</Name>
<Email>nilima@gmail.com</Email>
<Phone>9680464645</Phone>
<Gender>Female</Gender>
</Employee>
</Employees>

As desired result is similar ,difference in xml is minor; checkout where xml varies own yourself, though it will not make much difference to client consuming this web api.

Thanks, Happy Coding.