Search code examples
c#asp.net-web-api2httpclient

How to consume an ArrayList in c# from RESTful API?


I have deployed a REST API in IIS, in which a GET method returns an Arraylist of Student Class. How can I consume XML root Element "ArrayOfStudent" in c# using HttpClient? Below is the code I have written so far.

API get method

[HttpGet]
[ResponseType(typeof(IEnumerable<Student>))]
public IHttpActionResult Get()
{
     using (handler) //handler is just EF code to get data
     {
        return Ok(handler.Get());
     }
}

API XML response

<ArrayOfStudent xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Com.CompanyName.Component.Entity">
   <Student>
      <Id>1</Id>
      <Name>John</Name>
   </Student>
</ArrayOfStudent>

Http Client Code

 static void Main(string[] args)
        {

            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri("http://localhost:55587/");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));

            Task<HttpResponseMessage> responseTask = client.GetAsync("api/Student");
            responseTask.Wait();

            ///////Error is on this line of code ////////
            var ListTask = responseTask.Content.ReadAsAsync<IEnumerable<Student>>();
            ListTask.Wait();

            IEnumerable<Student> list = ListTask.Result;
            return list;

        }

Inner Exception

Inner Exception 1:
SerializationException: Error in line 1 position 150. Expecting element 'ArrayOfStudent' from namespace 'http://schemas.datacontract.org/2004/07/Com.CompanyName.ApiAgent.Entity'.. Encountered 'Element'  with name 'ArrayOfStudent', namespace 'http://schemas.datacontract.org/2004/07/Com.CompanyName.Component.Entity'. 

Student class -- Simple

using System;

namespace Com.CompanyName.Entity
{
    public class Student
    {
        public long Id { get; set; }
        public string Name { get; set; }

    }
}

Solution

  • Your xml is being serialized by the server with the DataContractSerializer. You can tell, because the namespace in your xml is http://schemas.datacontract.org/2004/07/Com.CompanyName. By default, the DataContractSerializer creates an xml namespace of http://schemas.datacontract.org/2004/07/{namespace}, where {namespace} is the C# namespace your class is defined in.

    So on the server side, your student class is defined like so:

    namespace Com.CompanyName
    {
        public class Student
        {
            public long Id { get; set; }
            public string Name { get; set; }
        }
    }
    

    Notice the difference in namespace. Your Student class is defined in namespace Com.CompanyName.Entity, which is why the DataContractSerializer has difficulty understanding the returned xml. Simply changing the namespace for your Student class to Com.CompanyName would solve your problem.

    However, this is pretty annoying, because that would mean you'd have to define all those classes in the same namespace as the server, and that would couple client and server very tightly. Fortunately, you can define your xml namespaces, and that is what I'd recommend you to do. Always use explicit namespace for your xml data contracts, to make the interchange more robust for future internal changes.

    On both the server and client side, define your Student class like this:

    [DataContract(Namespace = "http://companyname.com/schemas/student")]
    public class Student
    {
        [DataMember]
        public long Id { get; set; }
    
        [DataMember]
        public string Name { get; set; }
    }
    

    Now, we've defined a new namespace, and the xml would be serialized with the specified namespace. Because of this, it does not matter in which C# namespace you've defined your class anymore. Your xml would become something like this:

    <ArrayOfStudent xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://companyname.com/schemas/student">
       <Student>
          <Id>1</Id>
          <Name>John</Name>
       </Student>
    </ArrayOfStudent>
    

    You could also generate your C# classes from your xml. There are several tools available for this.