【问题标题】:Web Api response versioning solution?Web Api 响应版本控制解决方案?
【发布时间】:2013-03-25 14:57:49
【问题描述】:

在您认为这是重复之前,请稍等片刻。当我研究 Web Api 关于版本控制的问题时,一切都关心版本控制和在 url 与 headers 中指定版本的最佳实践。

我想弄清楚的是什么是版本输出响应的最佳方式,所以当我推出版本 2 时,我不会破坏版本 1 的客户端。

假设我有一个不断变化的 DAL,用于为网站和其他服务提供服务的网站套件。我正在开发一个新的 Web Api 项目,该项目的响应应该符合版本化模式。

我的问题是,在经过版本控制的控制器和未版本控制的 DAL 之前,在 Web Api 项目中实施版本控制的行之有效的解决方案/最佳实践是什么?

我提出了一个解决方案,其中涉及额外的版本化存储库层和额外的版本化模型层,因此版本化控制器使用使用版本化模型的版本化存储库。我已经设置 Automapper 在未版本化的域模型(来自 DAL)和版本化模型之间进行映射。但是这个设置的继承缺陷是,我必须为每个新版本更新所有地图;一个指数级增长的问题。

必须有更好的方法。谢谢!

【问题讨论】:

  • 这是一个很好的版本控制器解决方案,但就像我说的,我不是在寻找那个
  • 我唯一能想到的;将是创建一个包含该数据的自包含模型。然后使用控制器提取该信息。或者,拥有一个单独的数据库表,您可以在其中使用这些引用。不确定这是否有帮助,好问题我也会考虑一下。

标签: c# asp.net-mvc asp.net-mvc-4 asp.net-web-api


【解决方案1】:

根据我的经验,我们发现的最简洁(但不是最简单)的解决方案分为 5 个部分:

  1. 拥有权威的数据模型和始终保持最新的后端:DAL/数据库/服务。
  2. 拥有系统可以理解的版本特定数据:多数据模型。
  3. 确保正确识别和跟踪版本之间的更改,并且更改是可逆的。必须明确定义规则以处理该问题(这可能更难):转换器。
  4. 让客户端明确告诉您他们使用哪个版本:查询字符串/标题。
  5. 拥有始终保持最新但知道如何在不同数据版本之间移动的权威业务逻辑 - 向后兼容:控制器。

我们拥有的数据模型例如是供应商。

(1) 后端(即 DAL/数据库)为 V5。业务逻辑(即服务)也在 V5 中。

(2) 但是,我们需要同时为 V1、V2、V3、V4 上的客户供应商和 V5 上的最新客户提供服务。让我们将我们的数据模型从 V1 到 V5:SupplierV1、SupplierV2...(您可以使用命名空间或其他方式来区分它们)

(3) 您需要定义转换器并对其进行管理。他们必须处理数据模型版本之间的向前和向后兼容性。这可以通过策略模式、lambdas、具有 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,然后保存更新的数据,所有这些都在 Converter 中。这意味着您现在可以即时迁移后端。显然,这并不像听起来那么容易,因为您需要在同一个数据库中同时支持这两个版本,但根据您拥有的更改或数据的类型,它可能适合您。

【讨论】:

    【解决方案2】:

    我建议对您的模型进行版本控制。您可以通过命名空间来做到这一点,以保持简单。事实上,NServiceBus 为它的消息传递做了类似的事情。这是他们的例子:http://support.nservicebus.com/customer/portal/articles/894151-versioning-sample

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多