我有这个简单的模型类,其定义如下:
public class CountryLanguage
{
public string Name { get; set; }
public string ShortName { get; set; }
public string Description { get; set; }
}
我有这个Web API,它返回一个IEnumerable的CountryLanguage:
[HttpGet]
public IEnumerable<CountryLanguage> Get()
{
List<CountryLanguage> list = new List<CountryLanguage>();
list.Add(new CountryLanguage());
list.Add(new CountryLanguage());
return list;
}
我有这个类,我想存储Web API调用的结果:
public class ResponseResult<T>
{
public HttpStatusCode StatusCode { get; set; }
public string Message { get; set; }
public T Payload { get; set; }
}
最后,这是调用Web API的代码:
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, actionToCallWithParameters);
var response = httpClient.SendAsync(request).Result;
ResponseResult<T> responseResult = new ResponseResult<T>();
responseResult.StatusCode = response.StatusCode;
responseResult.Message = response.Content.ReadAsStringAsync().Result;
responseResult.Payload = response.Content.ReadAsAsync<T>().Result;
return responseResult;
如果Web API返回CountryLanguage对象,我没有将此对象存储到我的泛型类型属性有效内容中的问题。
但是如果Web API返回IEnumerable,我会收到此错误:
无法将当前JSON数组(例如[1,2,3])反序列化为类型“CountryLanguage”,因为该类型需要JSON对象(例如{\“name \”:\“value \”})才能正确反序列化。要修复此错误,请将JSON更改为JSON对象(例如{\“name \”:\“value \”})或将反序列化类型更改为数组或实现集合接口的类型(例如ICollection,IList)像可以从JSON数组反序列化的List。 JsonArrayAttribute也可以添加到类型中,以强制它从JSON数组反序列化。
我的问题是:是否可以“规范化”此代码,以便可以将对象或IEnumerable存储到T类型的有效负载属性中?
答案 0 :(得分:1)
通过此更改,我能够解决问题但我不认为它完全回答了您的问题。我将在下面给出你的答案的解决方案,但这是我为解决运行时问题而添加的内容,它会返回你的列表。
var responseResult = new ResponseResult<IEnumerable<CountryLanguage>>
{
StatusCode = response.StatusCode,
Message = response.Content.ReadAsStringAsync().Result,
Payload = response.Content.ReadAsAsync<IEnumerable<CountryLanguage>>().Result
};
基本上只需将T转换为IEnumerable,如果在类或方法中将T定义为CountryLanguage,则可以将其设置为IEnumerable,但是您的代码不会显示完整的类或方法。
现在回到您的另一个问题,从一个通用方法返回对象或对象列表。第一个响应是正确的,你只需要返回对象和box / unbox并使用反射和其他非常令人不快的代码,这些代码可能被封装但仍然有点令人讨厌。因此,如果您的目标是将此返回的有效负载用于CountryLanguage以外的其他内容,则可以尝试以下操作。创建一个名为PayloadWrapperthat的新类,包含两个属性,如:
public class PayloadWrapper<T>
{
public T Item { get; set; }
public IEnumerable<T> Items { get; set; }
}
然后你可以在你的webapi和客户端设置on或另一个,检查设置了哪个。
public PayloadWrapper<CountryLanguage> Get()
{
var languages = new List<CountryLanguage> {new CountryLanguage(), new CountryLanguage()};
var payload = new PayloadWrapper<CountryLanguage>();
payload.Items = languages;
payload.Item = null;
return payload;
}
在客户端:
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:34213/api/values/");
var httpClient = new HttpClient();
var response = httpClient.SendAsync(request).Result;
var responseResult = new ResponseResult<PayloadWrapper<CountryLanguage>>
{
StatusCode = response.StatusCode,
Message = response.Content.ReadAsStringAsync().Result,
Payload = response.Content.ReadAsAsync<PayloadWrapper<CountryLanguage>>().Result
};
您的Payload现在是一个包含一个项目或同一项目列表的单个对象。可用于发送符合此模式的任何内容。
答案 1 :(得分:0)
其实你的逻辑不对。如果在运行时您的T类型充当“CountryLanguage”类型,则您的Payload属性将充当CountryLanguage属性。这就是当您尝试将IEnumerable值分配给属性时抛出错误的原因,因为您将IEnumerable对象分配给不可枚举的属性。
基本上,在运行时,系统正在这样做:
CountryLanguage Payload = IEnumerable<CountryLanguage>(variable);
这显然会引发错误。
答案 2 :(得分:0)
好的,可以将IEnumerable存储到泛型类型T的变量中。
如果我希望返回的数据是一个对象,我需要进行的调用是:
ResponseResult<CountryLanguage> response = serviceConnector.GetData <CountryLanguage>(actionToCall);
如果我期待来自通话的IEnumerable:
ResponseResult<IEnumerable<CountryLanguage>> response =
serviceConnector.GetData<IEnumerable<CountryLanguage>>(actionToCall);
所以我的错误是我在调用代码时没有指定IEnumerable类型。