Web Api响应版本控制解决方案?

9
在你考虑这个问题是一个重复的问题之前,请再看一眼。当我在研究Web Api版本控制时,所有的关注点都集中在版本控制器和指定URL vs.标头版本的最佳实践上。
我试图弄清楚的是,在推出第二版时如何对输出响应进行版本控制,以便不会破坏第一版客户端。
假设我有一个持续变化的DAL,为一个网站套件提供数据,并提供给其他服务。我正在开发一个新的Web Api项目,应该具有符合版本化模式的响应。
我的问题是,在未经版本控制的DAL之前,Web Api项目实现版本控制的已证明的解决方案/最佳实践是什么?
我想出了一个解决方案,涉及到一个额外的版本化存储库层和一个额外的版本化模型层,因此版本化控制器使用版本化存储库,该存储库使用版本化模型。我已经设置了Automapper来映射未经版本控制的域模型(来自DAL)到版本化模型。但是,这种设置的固有缺陷是,我必须更新每个新版本的所有映射;这是一个呈指数增长的问题。
肯定有更好的方法。谢谢!

https://github.com/Sebazzz/SDammann.WebApi.Versioning - adt
这是版本控制器的一个很好的解决方案,但正如我所说,我不需要那个。 - Levitikon
我能想到的唯一解决方案是创建一个自包含的模型来保存这些数据,然后使用控制器来提取这些信息。或者,在单独的数据库表中利用这些引用。不确定这是否有帮助,这是个好问题,我也会考虑一下。 - Greg
2个回答

2
根据我的经验,我们找到的最干净(但不是最简单)的解决方案分为五个部分:
  1. 具有权威数据模型和始终保持最新状态的后端:DAL/数据库/服务。
  2. 具有版本特定的数据,系统可以理解:多数据模型。
  3. 确保正确识别和跟踪版本之间的更改,并且更改是可逆的。必须明确定义规则来处理它(这可能更难):转换器。
  4. 让客户端明确告诉您他们使用的版本:查询字符串/标头。
  5. 拥有始终保持最新状态但知道如何在不同数据版本之间移动的权威业务逻辑-向后兼容:控制器。
我们拥有的数据模型示例是供应商。 (1) 后端(即DAL/数据库)位于V5。业务逻辑(即服务)也位于V5。 (2) 但是,我们需要同时为客户端提供版本为V1、V2、V3、V4和最新客户端的供应商。让我们将数据模型的V1到V5命名为SupplierV1、SupplierV2...(您可以使用名称空间或其他方法来区分它们)。 (3) 您需要定义转换器并管理它们。它们必须处理数据模型版本之间的前向和后向兼容性。这可以使用策略模式、Lambda、带有DI转换器的管理器等方式完成。您需要处理V1->V2->V3->V4->V5以及V5->V4->V3->V2->V1。
转换器中的规则是最难的部分。有时很容易-新字段的默认值。其他时候,您需要运行一些业务逻辑。有时您需要转换/合并现有数据;您必须确保它是可逆的!例如,如果V1中的值为混合大小写,并将其转换为V2中的大写字母...您将无法将其返回到V1,因为您不知道哪些字符是大写和小写。您可以用两种方法处理它:
  • 在V1中保持它为大写字母。毕竟,只有V2需要它,V1可能可以使用所有大写字母(显然无法在键上工作)。
  • 在V2中的一个字段中保留旧值。例如,如果您决定将State字段转换为大写字母,则可以保留一个OriginalState,其中包含混合大小写,并在返回V1时将其复制到State中。
正如您所看到的,您需要考虑这些困难,而且通常并不是微不足道的。

(4) 在控制器中,您需要知道客户端使用的版本以便在需要时进行控制器内外的转换。为此,您可以使用查询字符串、头部信息(例如 X-API-Version 或 Accept,但要注意某些主机/代理会剥离它们的一些内容)、POST 参数等。

(5) 最后,当控制器接收到数据模型时,您需要检查客户端发送的版本(假设为 V2),并将其升级到后端的最新版本(V5)。然后正确使用它,如果需要发送数据回去,则需要将其降级为客户端版本(V2)。为此,您可以使用自定义绑定、自定义请求操作、自定义操作结果等。例如(请自动化处理):

public IHttpActionResult DoSomethingWithSupplier(JToken supplier) // Receiving Json Supplier
{
   // TODO: Get the client version type, for example in the X-API-Version header/query strings
   // (beware, some proxy/hosts strips some headers)
   // Type clientType = ...

   var clientSupplier = JsonConvert.DeserializeObject(supplier.ToString(), clientType);

   // You should probably detect latest version automatically (instead of typeof)
   var latestSupplier = VersionManager.Upgrade(clientSupplier, clientType, typeof(SupplierV5));

   outputSupplier = DoSomething(latestSupplier);

   // You should probably detect latest version automatically (instead of typeof)
   var clientOutputSupplier = VersionManager.Downgrade(outputSupplier, typeof(SupplierV5), clientType);

   return Ok(clientOutputSupplier);
}

这只是一个简单的示意图,我们在其中一个系统中使用。您可以拥有检测类型和版本并自行处理转换的管理器,可以使用依赖注入动态加载程序集/转换器,可以在自定义绑定/请求操作中自动执行大部分转换等。

注意: 还有一部分(6)您可能需要考虑。要将客户端数据实际更新到V5的数据库中,您可以在迁移到V5时进行批量数据迁移,或者在运行时进行。当您接收到SupplierV1时,您从数据库中加载该数据(仍为V1数据),进行升级为V5,并在转换器中保存更新后的数据。这意味着您现在可以对后端进行即时迁移。显然,这并不像听起来那么容易,因为您需要支持同一个数据库中的两个版本,但根据您具有的更改或数据类型,它可能非常适合您。


0

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