如何从 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。有多种工具可用于此。
我在 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。有多种工具可用于此。