使用ApiController与使用OData EntitySetController的区别

24

我刚开始学习ASP.NET Web API,还有几件事情不太清楚:

  • 为什么要使用EntitySetController,它继承自OData控制器,而不是ApiController?
  • 为什么在OData的上下文中经常提到EF。我知道它“表示”一个实体,但我不明白它们两者之间的联系。前者在服务层上,而EF是模型。
  • 我已经阅读并理解了很多相关的文献,但我错过了最佳实践的时间。

非常感谢,David


3
这并不是基于个人观点的问题。它甚至没有像是一个基于个人观点的问题。投票关闭的人是否可以在回答中出现分歧意见后再关闭呢? - Luke Puplett
这是一个非常好的问题,而且绝对不是基于个人观点的。 - David Tansey
2个回答

45

为什么我应该使用从OData Controller继承的EntitySetController而不是ApiController

  • 我同意这很困惑,文档似乎缺乏(至少当我有和你一样的问题时)。我放心的方式是通过简单地阅读代码来消除我的疑虑。我鼓励你也这样做,因为它真的非常简短(专注于EntitySetController类及其helpers);最多只需要5-10分钟的时间(保证),并且之后你将不会有任何问题。

    简而言之,它消除了一些常见情况下的模板代码(但如果您想要更多背景信息和观点,请继续阅读)。

为什么在OData的上下文中经常提到EF?我知道它"代表"一个实体,但我不明白它们两者之间的联系。第一个是服务层,而EF是模型层。
  • 这个问题也曾让我困扰了很久,直到我放弃并查看了OData的起源,WCF Data Services(之前是ADO.NET Data Services)和OData规范(提示是OData Core协议版本仍然使用名为“DataServicesVersion”的标头)。在那里,你可以发现OData使用EDM,即实体数据模型,这是EF使用的相同模型规范,并以与EF相同的格式序列化它:CSDL(概念模式定义语言)。这不是巧合,WCF Data Services对EF有着重要的支持,虽然它不需要,但可以说它的设计基于EF。

    请注意,WCF Data Services 仍然是 OData的旗舰实现。

以下是一些可能非常有趣的内容(至少我认为很有趣):当使用EF与ASP.NET Web API和OData扩展时,据我所知,没有办法共享模型。

如果你觉得这个问题不感兴趣,可以跳到下一个问题。

例如,在使用EF进行Code-First设置时,您通常会根据代码约定和EF的System.Data.Entity.DbModelBuilder("fluid API")构建模型。然后,您将使用System.Web.Http.OData.Builder.ODataConventionModelBuilder来构建OData模型,几乎完全相同,并且得到几乎完全相同的结果。过去,我曾经从EF团队或Web API团队的某个随机会议中找到了一些随机笔记,其中简要提到了这一点,就我所知(我无法再找到此文档),他们没有计划改善这种情况。因此,现在他们有两个不同且不兼容的EDM实现。

我承认我没有花时间仔细查看代码以正确验证这一点,但我知道Web API + OData扩展依赖于EdmLib(最初为WCF数据服务提供Microsoft.Data.Edm),而EF则不是这样,并且使用自己的System.Data.Entity.Edm实现。我也知道它们基于约定的模型生成器是不同的,如上所述。如果你在DB-First设置中使用EF,情况就变得荒谬了;你会在EDMX文件中获得一个以CSDL格式序列化的EDM模型,而OData扩展会在运行时从由EF从初始CSDL通过T4模板生成的CLR代码(使用单独的代码约定)中生成自己的序列化CSDL代码。你的头会晕吗?


更新: 这在不到两周前(7月19日)得到了很大的改进,对此我感到非常抱歉。 (感谢RaghuRam Nadiminti)。我没有审查补丁,但从示例代码中看来,它的工作方式是必须使用EF EDMX序列化程序将模型序列化为CSDL,然后使用EdmLib解析器进行反序列化以供OData扩展使用。 在EF Code-First设置中仍然感觉有点像黑客(至少CLR代码只被分析一次,但我更喜欢两个组件最初使用相同的内存模型)。 然而,在使用Model-First或Database-First场景时可以采用快捷方式,直接反序列化由VS生成的EDMX文件。 在这种情况下,它实际上感觉不像黑客,但同样,单个模型是最好的选择。 我不知道EF是否可能切换到使用EdmLib,或者EdmLib是否会切换到使用EF的EDM模型,这两个项目现在都非常强大,阻碍因素可能不仅仅是技术问题。 据我所知,ASP.NET团队无法对此做出太多贡献。

更新: 偶然再次发现那些会议记录。它们确实来自EF团队,并表明他们不打算继续开发EdmLib。
然而,我现在认为这是一件好事。原因是,如果他们关闭所有间隙,并删除所有样板文件,并使一切正确,他们将最终到达WCF Data Services所在的位置,这是一个完全集成的解决方案,程序员通过“拦截器”在管道中注入代码。对我而言,前往那里的唯一原因是开源要求,但即使如此,我认为推动一个开源的WCF-DS更加合理。

问题现在变成了:“那么Web API + OData扩展有什么用处呢?”当你真正想要数据存储和Web服务两个不同的模型时,它非常适合。当“拦截器”设计对于你来说不够灵活,不能在两个模型之间进行转换时,它非常适合。


更新:截至2014年3月27日,官方确认,他们将尝试关闭这些差距,并废弃WCF数据服务。非常早期的讨论提到了一个“处理程序”来完成此操作,最有可能的是ASP.NET HTTP处理程序(请参见公告上的评论)。看起来他们几乎没有进行规划,因为他们仍在集思广益如何使ASP.NET Web API填补WCF数据服务的用例。我在公告的评论和这个主题中提到了那些用例(发表于公告前几天)。
许多其他人表达了非常相似的担忧(再次,请参见链接的讨论),所以很高兴看到我没有做白日梦。
有人不相信ASP.NET Web API能在合理的时间内转变为数据服务用例中有用的东西,因此有人建议微软重新考虑他们的决定。是否使用ASP.NET满足开源需求的问题也没有意义:如果一切顺利,WCF数据服务将很快成为开源软件,但并非由于任何倡导努力。(这只是一个源码存储库,目前尚不清楚是否有人会维护它。)
从我所了解的情况来看,一切都指向预算削减,有些人认为这是公司整体“重新聚焦”的结果,但这些都应该谨慎对待。
除此之外,现在有可能出现一种新的解决方案——甚至比WCF Data Services或Web API更好,特别是针对OData API。虽然现在看起来有些混乱,但MSFT OData团队相对早期就收到了客户的反馈,所以仍然存有希望(尤其是如果未来的解决方案本身是开源的)。转换可能会很痛苦,但请确保关注未来的讨论。
我不确定是否会再更新这篇文章;我只是想强调,关于Web API和Data Services的事情即将发生重大变化,因为这个答案仍然时不时地被点赞。

更新: RESTier (公告) 似乎是结果。



最后,我(个人)的观点是:尽管 OData 在技术上是一种基于 RESTful HTTP 的协议,但它非常、非常、非常注重数据。这完全没问题(我们可以使用 HTTP 定义许多不同类型的接口),我个人认为 ServiceStack 与 OData 的争论无关紧要(我认为它们在我们当前共同的架构中运行在不同的层次)。我担心的是人们试图让基于 OData 的 API 像面向行为(或“过程导向”或类似 ServiceStack 的)API 一样运作。对我来说,OData URI 约定和资源表示格式(Atom 和 JSON)一起替代了 SQL,WCF 数据服务 "查询拦截器" 和 "更改拦截器" 替代了 DBMS 触发器,OData 操作 替代了 DBMS 存储过程。从这个角度来看,你会立刻发现,如果你需要在 OData API 后面放置的领域逻辑过于复杂或者不太注重数据,你将会得到不符合 REST 原则的复杂“操作”,以及感觉不正确的实体。如果你把你的 OData API 当作一个纯数据层,那就没问题。你可以像在 SQL 数据库上放置“服务层”一样,在其上堆叠服务。
因此,我不确定Web API + OData扩展是否还那么好。如果您需要根本不同的模型,那么很可能您的应用程序并不太数据导向(除非您只是从各种来源合并模型之类的操作),因此OData并不适合。这表明您至少应该考虑仅使用Web API(下面介绍SQL或OData)或类似ServiceStack的东西。
无论好坏如何,Javascript客户端无法向远程服务器发送SQL。也许将来可以通过浏览器API或通过 WebSockets的变体,但现在,OData是任何富JS客户端获取远程数据层的最接近的东西,而这些客户端具有薄或没有服务器端逻辑。当然,OData也被其他类型的客户端使用,但我认为它在客户端Web平台上特别有用,其中像Breeze.js或JayData之类的工具与OData相当于Entity Framework与SQL之间的关系。

我已经阅读并理解了大量关于此主题的文献,但我错过了最佳实践的时间

  • 不用担心,我四处打听过了,但我认为没有人真正知道自己在做什么。在理清这个混乱之前,只需要像其他人一样装作就可以了。

1
很棒的回答。唯一需要注意的是,Web API OData可以支持外部生成的IEdmModel。这个问题现在已经被解决了。因此,如果你想将你的数据库原封不动地暴露出去,现在就可以了。 - RaghuRam Nadiminti
更新了您的补丁的解释(顺便说一句,做得很好,希望我理解得没错!)。 - tne
1
感谢您提供如此详尽的回答,我非常欣赏。我最喜欢您对上一个问题的回答,哈哈,虽然我希望在未来几年里这个答案不再适用。 =) - Tim Hong
我们回到了OData V4的起点,因为他们没有实现分离接口模式。Microsoft.Data.Edm和Microsoft.OData.Edm有自己独立的IEdmModel定义。太棒了。 - Richard Collette

0

如果您想创建一个OData端点,请使用EntitySetController。如果您想返回通用的JSON或XML,或者其他格式(例如使用自定义格式化程序),请使用ApiController。

在Web API中,EF和OData不一定是相互关联的。您可以编写一个不使用EF的OData端点。许多Web API教程使用EF,因为EF代码优先相对容易在教程中展示。:-)


谢谢,但我什么时候需要一个OData端点呢?例如,我有一个类“A”,还有3个继承自A的其他类:A1、A2和A3。我想为A1、A2和A3公开CRUD操作。我应该为它们每个人(我确实想要3个不同的控制器)创建一个ApiController还是EntitySetController? - david lopez
通常情况下,每个“服务”都需要一个单一的终端点;这是一项架构决策。每个Web API代表一个OData终端点(我所说的Web API是“将ODataRoute和EDM模型映射到的东西”)。一个模型有多个实体(你的三个类)。每个实体由一个单独的ODataController控制,可能是一个EntitySetController(它只是扩展了ODataController类)。 - tne
ODATA端点可以执行API端点所能执行的所有功能,为什么需要两者并存呢? - Sundara Prabu

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