反序列化Web Api OData响应

本文关键字:响应 OData Api Web 反序列化 | 更新日期: 2023-09-27 18:16:46

我有一个OData V4控制器返回的实体框架对象。我返回一个IQueryable,如果我调用没有任何OData子句的OData端点,我可以成功地做到这一点:

var content = response.Content.ReadAsAsync<IQueryable<Person>>();

JSON格式的响应如下:

{
  "@odata.context":"http://xxx:8082/odata/$metadata#Persons","value":[
    {
      "Id":"291b9f1c-2587-4a35-993e-00033a81f6d5",
      "Active":true,
      "Alert":"Some alerts for the Person",
      "Comments":"Some comments for the Person"
    }
  ]
}

但是一旦我开始使用OData,例如通过在Complex属性上使用$expand,我就会得到以下异常:

无法将当前JSON对象(例如{"name":"value"})反序列化为类型'System.Linq.IQueryable ' 1[xxx. xxx]。

,因为该类型需要一个JSON数组(例如[1,2,3])来正确反序列化。

响应如下:

{
  "@odata.context":"http://aqavnext01:8082/odata/$metadata#Persons","value":[
    {
      "Id":"291b9f1c-2587-4a35-993e-00033a81f6d5",
      "Active":true,
      "Alert":"Some alerts for the Person",
      "Comments":"Some comments for the Person",
      "Party":{
        "Id":"291b9f1c-2587-4a35-993e-00033a81f6d5"
      }
    }
  ]
}

我正在使用我的Web Api返回的相同对象进行反序列化,所以我不明白为什么它失败了。同样的问题,当我应用$select.

反序列化Web Api OData响应

尝试像这样反序列化内容:

var content = response.Content.ReadAsAsync<ODataResponse<Person>>();

其中odatresponse为:

internal class ODataResponse<T>
{
    public T[] Value { get; set; }
}

如果需要访问响应JSON中的@odata.xxx字段(例如实现分页结果的循环),下面是我的实现,它扩展了andygjp的解决方案。

我使用RestSharp作为我的HTTP客户端和Json。. NET用于(反)序列化。步骤如下:

实现使用Json的自定义IRestSerializer。. NET来替换默认的RestSharp序列化器。下面的示例实现:

public class JsonNetSerializer : IRestSerializer
{
    private readonly JsonSerializerSettings _settings;
    public JsonNetSerializer()
    {
        _settings = new JsonSerializerSettings
        {
            NullValueHandling = NullValueHandling.Ignore
        };
        _settings.Converters.Add(new StringEnumConverter());
    }
    public string Serialize(Parameter parameter) => JsonConvert.SerializeObject(parameter.Value, Formatting.None, _settings);
    public string Serialize(object obj) => JsonConvert.SerializeObject(obj, Formatting.None, _settings);
    public T Deserialize<T>(IRestResponse response) => JsonConvert.DeserializeObject<T>(response.Content);
    public string[] SupportedContentTypes => new string[] { "application/json", "text/json", "text/x-json", "text/javascript", "*+json" };
    public DataFormat DataFormat => DataFormat.Json;
    public string ContentType { get; set; } = "application/json";
}

接下来,定义一个表示OData响应的类。我的扩展响应类(包括@odata.nextLink字段)如下所示。

private class ODataResponse<T>
{
    public T[] Value { get; set; }
    [JsonProperty("@odata.nextLink")]
    public string NextLink { get; set; }
}

最后,创建RestClient的一个实例,设置前面创建的自定义序列化器:

var client = new RestClient("https://base.url.here/")
    .UseSerializer(() => new JsonNetSerializer());

现在,当我执行请求时,响应对象对象中的数据也包含我的OData值。

var response = await client.ExecuteAsync<T>(request);
var nextLink = response.Data.NextLink;

我确信这可以使用标准的HttpClient而不是RestSharp来完成,因为真正的工作是由序列化器完成的。这只是我手头的示例实现。