如何从 RESTful API 使用 c# 中的 ArrayList?

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

我在 IIS 中部署了一个 REST API,其中一个 GET 方法 returns 一个 Student Class 的数组列表。如何使用 HttpClient 在 c# 中使用 XML 根元素 "ArrayOfStudent"?以下是我到目前为止编写的代码。

API获取方法

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

APIXML响应

<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 客户端代码

 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 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'. 

学生class -- 简单

using System;

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

    }
}

很抱歉之前的不相关我需要先见学生 class 才能给你答案,你必须改变你的学生 class 或创建新的作为模型并传递给你实体,您需要包含以下两个 classes 以便将您的 XML 序列化为您想要的对象/列表

   [XmlRoot("ArrayOfStudent")]
   public class ArrayOfStudent
   {
   [XmlElement("Student")]
   public IEnumerable<Student> Students { get; set; }
   }

   public class Student
   {
   [XmlElement("Id")]
   public int Id { get; set; }
   [XmlElement("Name")]
   public string Name { get; set; }
   }

您需要从 xml 序列化到对象的代码:

     HttpResponseMessage response = client.GetAsync("api/Student");
     var readAsStringAsync = response.Content.ReadAsStringAsync();
     string result = readAsStringAsync.Result;
     XmlSerializer serializer = new XmlSerializer(typeof(ArrayOfStudent));
     using (TextReader reader = new StringReader(result))
     {
     ArrayOfStudent result = (ArrayOfStudent) serializer.Deserialize(reader);
     }

以下只是为了改进您的设计,没有必要。 始终建议对此类请求使用通用代码,如下所示 class 它可以节省您很多时间,而且您几乎可以在任何地方使用它。

    public class ApiResult<T>
  {
    public IEnumerable<T> List { get; set; }
    public T Object { get; set; }
    public string Message { get; set; }
    public bool Success { get; set; }
    public HttpStatusCode StatusCode { get; set; }
    public string Url { get; set; }
    public static ApiResult<T> Post(string uri, string url, string token = null)
    {
        using (var client = new HttpClient())
        {
            client.Timeout = TimeSpan.FromMilliseconds(1800000);
            client.BaseAddress = new Uri(uri);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
            if (!string.IsNullOrEmpty(token))
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", token);
            }
            HttpResponseMessage response = client.PostAsync(url, null).Result;

            return Result(response);
        }
    }

    public static ApiResult<T> Get(string uri, string url, string token = null)
    {
        using (var client = new HttpClient())
        {
            client.Timeout = TimeSpan.FromMilliseconds(1800000);
            client.BaseAddress = new Uri(uri);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
            if (!string.IsNullOrEmpty(token))
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", token);
            }
            HttpResponseMessage response = client.GetAsync(url).Result;
            return Result(response);
        }
    }
    private static ApiResult<T> Result(HttpResponseMessage response)
    {
        ApiResult<T> result = response.Content.ReadAsAsync<ApiResult<T>>().Result;
        if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden)
        {
            result.StatusCode = response.StatusCode;
        }

        if (response.IsSuccessStatusCode)
        {
            result.Success = true;
        }
        return result;
    }
}

如果你实现了上面的方法,现在你可以这样写你的 main 方法 class:

    static void Main(string[] args)
    {
      // both Uri & Url u can get it from ur app.config or web.config to make it easier to edit on publish saves you alot of time.
       string Uri = "http://localhost:55587"; 
       string Url = "api/Student";
       string token = "yourtoken"; //(optional)
       ApiResult<Student> result = ApiResult<Student>.Get(Uri, "/" + Url, token);
        if(result.Success && result.List.Any())
       {
        IEnumerable<Student> list = result.List;
        return list;
       }
       else
       //return error if result.success is false else there are no records... 
    }

您的 xml 正在由服务器使用 DataContractSerializer 序列化。你可以看出,因为你的 xml 中的命名空间是 http://schemas.datacontract.org/2004/07/Com.CompanyName。默认情况下,DataContractSerializer 创建 http://schemas.datacontract.org/2004/07/{namespace} 的 xml 命名空间,其中 {namespace} 是定义 class 的 C# 命名空间。

所以在服务器端,你的学生 class 是这样定义的:

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

注意命名空间的不同。您的 Student class 定义在命名空间 Com.CompanyName.Entity 中,这就是 DataContractSerializer 难以理解返回的 xml 的原因。只需将 Student class 的名称空间更改为 Com.CompanyName 即可解决您的问题。

然而,这很烦人,因为这意味着您必须在与服务器相同的命名空间中定义所有这些 classes,这将非常紧密地耦合客户端和服务器。幸运的是,您可以定义 xml 名称空间,这就是我建议您做的。始终为您的 xml 数据协定使用显式命名空间,以使交换对于未来的内部更改更加稳健。

在服务器端和客户端,像这样定义你的 Student class:

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

    [DataMember]
    public string Name { get; set; }
}

现在,我们已经定义了一个新的命名空间,xml 将使用指定的命名空间进行序列化。因此,您在哪个 C# 命名空间中定义 class 不再重要。你的 xml 会变成这样:

<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>

您还可以从 xml 生成 C# classes。有多种工具可用于此。