2014-02-19 140 views
1

我有这样定义这个简单的模型类:我有这个网页API,返回CountryLanguage的IEnumerable存储结果

public class CountryLanguage 
{ 
    public string Name { get; set; } 
    public string ShortName { get; set; } 
    public string Description { get; set; } 
} 

[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)像List,可以从JSON数组中反序列化。 JsonArrayAttribute也可以添加到类型中,以强制它从JSON数组反序列化。

我的问题是:是否有可能“正常化”此代码,所以我可以存储一个对象或IEnumerable到我的有效载荷属性的T型?

回答

0

好了,就可以到IEnumerable存储到泛型类型T.

的变量,如果我希望返回的数据是一个对象,调用我需要做的是:

ResponseResult<CountryLanguage> response = serviceConnector.GetData <CountryLanguage>(actionToCall); 

如果我期待的IEnumerable从呼叫:

ResponseResult<IEnumerable<CountryLanguage>> response = 
       serviceConnector.GetData<IEnumerable<CountryLanguage>>(actionToCall); 

所以我的错误是一个事实,即调用代码时,我并没有指定IEnumerable的类型。

0

其实你的逻辑不正确。如果在运行时你的T类型是'CountryLanguage'类型,那么你的Payload属性就像CountryLanguage属性一样。这就是为什么当您尝试将IEnumerable值分配给属性时会引发错误,因为您将IEnumerable对象分配给非可枚举属性。
基本上,在运行时,该系统是这样做的:

CountryLanguage Payload = IEnumerable<CountryLanguage>(variable); 

这显然会抛出一个错误。

+0

是的你是对的。但是,您能想出任何可以将对象或IEnumerable的结果存储到一个泛型类型变量中的方法吗? – Elferone

+0

是的,如果您使用“对象”类型声明有效载荷,则可以在其中存储任何内容。但是拆开它以后再使用会遇到很多麻烦。如果我是你,我会将Payload设置为列表列表。然后,我会让服务总是返回一个List 对象,即使只填充了一个索引。 – LcSalazar

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类或方法,那么你可以将其设置为IEnumerable的定义为CountryLanguage但您的代码不显示完整的类或方法。

现在到您的其他问题,从一个通用方法返回对象或对象列表。第一个反应是正确的,你只需要返回对象和box/unbox,并使用反射和其他非常不愉快的代码,这些代码可能被封装,但仍然有点麻烦。因此,如果您的目标是将此返回的有效内容用于CountryLanguage以外的其他内容,则可以尝试以下操作。创建一个名为PayloadWrapperthat新类包含两个属性,像这样:

public class PayloadWrapper<T> 
{ 
    public T Item { get; set; } 
    public IEnumerable<T> Items { get; set; } 
} 

然后你可以设置或其他在你的WebAPI,并在其上设置客户端检查。

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

你的有效载荷现在是一个单一的对象,要么包含一个项目或同一项目的列表。可用于发回符合此模式的任何内容。