在API和应用程序之间共享对象的模式


9

我对我的Web应用程序的设计有严重的怀疑。

我想将业务逻辑与接口分开,所以我制作了一个Web API,用于处理对数据库的所有请求。

它是具有实体框架,工作单元和通用存储库模式的ASP.NET Web API。到目前为止,一切都很好。

问题

我需要帮助的地方是,我找不到在API和应用程序之间共享对象的有效方法。

我不想直接序列化实体对象,我认为这将是一个坏习惯,因为如果实体模型发生更改,我最终可能会无缘无故地序列化大型对象。

现在如何实施

因为我的接口是C#中的ASP.NET Web应用程序,而我的API是C#中的API,所以我创建了一个公共库,其中定义了我想在它们之间共享的所有类。

我知道当我开发一个Android应用程序时该解决方案将不起作用,我将不得不再次用Java创建类,但这不是我最大的问题。

问题是我感觉自己一直在转换对象。

这是我的工作流程示例:

我从包含所有对象和表单数据注释的模型开始,然后用户将模型发布到控制器。

在控制器中,我必须将此模型转换为我的公共库中的类,然后将该对象发送到我的API。

然后,我的API中的控制器捕获了该调用,并将该对象转换为实体对象以更新数据库。

所以我有3节课

  1. 视图的模型以及用于验证的所有数据注释(客户端)
  2. 共享对象的公共库类(DLL)
  3. 实体类(API)

我感觉自己做错了什么。还有更优雅的东西吗?我想确保在这个项目变得太大之前,我有一个很好的解决方案。


如果我的问题不清楚,请随时提出问题。
马克

对我而言,您不清楚实现的是哪种体系结构(也许是让.NET措辞困扰的我)-它是3层体系结构:客户端,服务器,数据库吗?
安迪

是的,我有一个使用Web API的Web应用程序。该API是具有数据库业务逻辑的API。
2014年

Answers:


12

我知道您似乎一直在不断地在数据库对象,数据传输对象,带有验证逻辑的客户端对象之间来回转换对象,但我会说不,您没有做错任何事情。

这些对象中的每一个都可以代表相同的信息单元,但是它们的职责却非常不同。数据库对象是您与数据库的通信接口,应保留在数据库层中,因为它可能有也可能没有不同的数据库元数据注释和/或其中的有关数据库实现的不必要的详细信息。

您的数据传输对象是与API使用方的通信接口。它们应尽可能干净,以方便从不同语言/平台中消费。根据您希望支持的API使用者,这可能会对它们的外观和行为施加某些限制。

具有验证逻辑的客户端对象实际上不是您的API项目的一部分,而是您的使用者项目的一部分。在这种情况下,它们不能与数据传输对象相同,因为您要在其上添加额外的客户端特定的逻辑(在这种情况下为验证属性),而服务器对此一无所知(也不应该知道!)。将这些对象算作您的API的一部分,因为它们实际上不是。它们是特定于用户的应用程序,某些使用您的API的应用程序甚至可能实际上甚至不需要创建这些对象,并且也可以仅在您的数据传输对象上生存。例如,如果您不需要验证,则不需要额外的与数据传输对象完全相同的对象层。

在我看来,这三种对象类型中的每一种似乎都很好地映射到一个职责,即干净的编码和良好的实践。可悲的是,干净的代码和良好的做法有时意味着您正在编写大量额外的代码,并且“只是因为”而跳过了额外的麻烦。而且在编码时,可能很难理解它给您带来的价值-但是,一旦您发布应用程序并开始支持它或为下一个版本添加新功能,您可能会开始意识到花了一些时间来首先适当地分离这些问题。(更不用说你

我也讨厌这样在不同对象类型之间编写转换代码,但是我的解决方案通常是以下之一:

  • 使用可以为您完成大部分对象转换工作的库-例如,如果您使用C#,则可以使用出色的AutoMapper库(http://automapper.org/)。我相信还有许多其他类似的库,但是AutoMapper是迄今为止我所见过的最强大的库。
  • 如果找不到库来帮助您进行对象转换,请编写一组实用程序方法以在它们之间进行转换。这可能很烂,但是从长远来看,这是值得的,第一次需要转换内容时,请编写转换方法-不要等待。

谢谢您的解释,但我仍然很难理解。我不明白为什么数据传输层没有任何验证?如果我忘记了下一个移动应用程序的验证,该怎么办?至少当我调用API而不是在数据库模型中执行异常时,它不会验证。我不确定我是否理解。
Marc

1
我并不是说您不应该在API级别进行验证。老实说,这是最重要的验证地点。在您的应用程序中进行验证只是一项“不错的功能”,可帮助您的用户避免犯错,验证您的数据传输对象是为了防止恶意和错误数据。但是,由于这些是不同的用例,因此您可能需要使用不同的验证框架(如果您的应用程序和api不是用相同的语言编写的,则将使用不同的验证框架),并且在每个级别上验证的内容可能会略有不同(续) (在下
一条

1
因此,您应该验证数据传输对象。但是您还应该确保验证它们的方式不会偶然引入任何其他框架的依赖。当然,正如我之前说的,您真的不能确定您的数据传输对象是否已经全部验证,或者它们是否已通过相同的框架验证-因此您必须“两次验证”。
wasatz

2
主要是,您应该尝试将您的应用程序和API视为两个完全不同且独立的应用程序。您可能同时开发它们,并且它们可能在同一个Visual Studio解决方案/ Eclipse项目中。但是它们实际上是两个完全独立的程序。当您在应用程序中工作时,请尝试“忘记”自己是创建API的人,就像使用普通的第三方API一样使用它。这样,您将更有机会了解其他人在使用您的API时的感受,并尽早纠正最糟糕的部分。
wasatz

1
当然,在处理API项目时也是如此,请尝试想象您正在编写许多第三方开发人员将要使用的服务。尽量不要过多考虑您当前的应用程序,而要多加注意“我提供的服务”,并假设所有使用您的API的人(包括您自己)都是邪恶的人,他们企图杀死您的服务器并使您删除整个数据库。
wasatz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.