反序列化 Web Api OData 响应

3

我有一个通过OData V4控制器返回的Entity Framework对象。我返回了一个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,例如在复杂属性上使用$expand时,就会出现以下异常:无法将当前JSON对象(例如{"name":"value"})反序列化为类型“System.Linq.IQueryable '1 [xxx.Person]”,因为该类型需要一个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时也有相同的问题。


你能提供更多类似控制器和数据模型的代码吗?另外可能与你的问题不直接相关,$expand用于导航属性而不是复杂类型。 - QianLi
我只是返回了一个 DbContext 集合。问题在于 C# 中的反序列化,在 Javascript 中我们完全没有问题。返回 dbContext.Set<Person>() - Raffaeu
2个回答

8
尝试像这样反序列化内容:
var content = response.Content.ReadAsAsync<ODataResponse<Person>>();

这里的ODataResponse是:

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

0

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

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

实现一个自定义的IRestSerializer,使用Json.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来完成这个任务,因为真正的工作是由序列化器完成的。这只是我手头上的一个示例实现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接