【问题标题】:Web API with OData and Entity Framework - Serialization Issue具有 OData 和实体框架的 Web API - 序列化问题
【发布时间】:2014-10-08 11:42:57
【问题描述】:

在我的 Web API 应用程序中,如果我在 Get 方法中使用 OData 来过滤结果,我会得到不一致的结果。没有OData 过滤器,结果很好。 在使用 OData 时,序列化的处理方式是否不同? 我这样做是否正确?

使用 OData:

我不明白 $ref 条目是什么,为什么它们是随机的,为什么我不使用 OData 时得不到它们??

这是Web API 方法:

public HttpResponseMessage Get(System.Web.Http.OData.Query.ODataQueryOptions<Employee> options)
        {
            HttpResponseMessage response;

            var employees = options.ApplyTo(_unitOfWork.EmployeeRepository.Get());

            if (employees == null)
            {
                response = new HttpResponseMessage(HttpStatusCode.NotFound);
            }
            else
            {
                response = Request.CreateResponse(HttpStatusCode.OK, employees);
                response.Content.Headers.Expires = new DateTimeOffset(DateTime.Now.AddSeconds(300));
            }
            return response;
        }

这是要序列化的类:

 public class Employee
    {
        [Key]
        public string WinId { get; set; }
        public string XML { get; set; }
        public int EffectiveYear { get; set; }
        public int FileKeeperGroupId { get; set; }
    }

编辑 8/15

这是我的 WebApiConfig

 var json = config.Formatters.JsonFormatter;
            config.Formatters.Clear();
            config.Formatters.Add(json);
            config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = 
                Newtonsoft.Json.PreserveReferencesHandling.None;

【问题讨论】:

  • 不清楚您使用 OData 的意义?您的意思是使用 ODataController 而不是 ApiController?能否也展示一下您使用 OData 的代码?

标签: c# json entity-framework asp.net-web-api odata


【解决方案1】:

不推荐使用的答案:
如本主题Entity relations in odata-v4 中所述,请查看以下部分:

在实体之间建立关系

OData 支持创建或删除两个现有的关系 实体。在 OData v4 术语中,关系是“参考”。 (在 OData v3 中,这种关系称为链接。协议 对于本教程,差异并不重要。)

引用有自己的 URI,格式为 /Entity/NavigationProperty/$ref。例如,这里是 URI 解决产品与其供应商之间的引用:

http:/host/Products(1)/Supplier/$ref

所以本质上它是 odata 了解哪个实体具有另一个实体的导航属性的方式。 WebApi 不知道什么是什么,它所做的只是为数据提供服务。但是,使用 OData,您可以在 URL 本身 中创建客户端查询,而不是在 c# 的后端使用 linq(就像您使用 web api 一样)。为了让 odata 正确查询后端,它需要了解数据库上下文中的所有实体和关系;这是通过首先检查您的 ODataController 提供的 $metadata 来完成的。您可以通过查看来验证这一点

http://localhost/api/User/$metadata

注意:假设您的控制器名为 UserController

请阅读有关 odata 的更多信息,并习惯于 odata 需要这些围绕数据的额外信息才能正确理解您的数据库。如果您不完全满意,您可以随时用 c# 编写 linq 查询并坚持使用 webapi(尽管您确实失去了 odata 的一些优势,您可以自己研究)。

新答案 (8/15)
编辑:根据下面的 cmets,绝对是导致问题的 json 序列化而不是 OData 序列化。很好地找到设置,因为这个站点:PreserveReferenceHandling,讨论了在 JSON 响应中保留引用的配置。

我们意识到 $ref 用于 OData 中的导航属性,我们还发现 $ref 用于在序列化和反序列化 json 时跟踪对象引用。

就个人而言,我宁愿将 $ref 留在其中,因为 JSON.NET 足够聪明,可以发现循环引用。如果您不相信我,请查看这篇文章:Serializing Circular References。但这都是个人喜好。

【讨论】:

  • 我的类中没有任何关系或导航属性,并且 ODataController 不是使用 OData 的先决条件。
  • 首先,我从来没有说过 ODataController 是先决条件。其次,我的信息并非无效,它也适用于您通过 ODataQueryOptions 处理 OData 的方式。第三,这就是你得到这些随机 $ref 的原因,因为你没有任何导航属性。如果你这样做了,那么那些随机的 $ref 就有意义了。您问的是关于 $ref 的问题,但您真正要问的是为什么 OData 会在您的数据中引入所有这些信息。它告诉 OData 您拥有的每个实体都没有任何导航属性。不要野蛮。
  • 野蛮?我不这么认为。但是,您的评论更有帮助。如果我没有导航属性(参见模型),那么我怎样才能获得随机 $ref?导航属性是先决条件吗?
  • 谢谢!导航属性不是先决条件。顺便说一句,您是否使用 Newtonsoft JSON.NET 序列化您的 EF?因为这甚至可能不是 OData 问题。一些序列化程序倾向于保留对象引用,因此它可能是由循环引用引起的。所以为了防止崩溃, $ref 可能会在那里规避它。如果您要直接序列化您的 EF 实体,我宁愿先创建一个视图模型。
  • 请查看我的编辑/更新,谢谢。 PreserveReferencesHandling.None 与 PreserveReferencesHandling.Objects 的区别在于空白 $ref
【解决方案2】:

从描述中您似乎不熟悉 OData 概念(如果我观察错误,请纠正我)。 OData 是用于编写 RESTful 服务和客户端的开放标准 (an OASIS standard),并且在 OData 中定义了某些约定和规则,它们与其他类型的 RESTful 服务不同。 ASP.NET Web API 支持 OData 版本 1-3 和 OData 版本 4.0。如果您想在您的 Web API 服务中启用此类支持,您应该知道您正在编写 OData 服务,并且只有 OData 特定客户端才能与您的服务对话。

在 OData 中处理序列化的方式与处理常见 Web API 服务的方式非常不同。原因是 OData 具有非常特殊的有效负载类型,需要特殊处理。让我们以 OData V4 JSON 有效负载为例。它有很多常见的 JSON 有效负载处理程序没有专门知识的 OData 特定 JSON 元素和属性。

您附加的负载不是 OData 负载,您附加的控制器操作也不是 OData 控制器操作。编写OData服务,可参考ASP.NET learning site了解详情。

【讨论】:

  • 这对我有什么帮助?
猜你喜欢
  • 2012-11-07
  • 2013-01-10
  • 2011-05-02
  • 2015-04-28
  • 1970-01-01
  • 2013-05-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多