WCF / SOA-为什么要为简单请求创建参数对象


12

我们公司正在启动一个相当大的SOA计划。我们正在做很多正确的事情:良好的沟通;在适当的地方购买工具的钱;并且我们已经引进了一些优秀的专业知识来帮助我们过渡。

我们正在尝试制定可以作为一个整体遵循的标准,其中一项提议的标准使我颇为困扰:

我们已经在模式上进行了标准化,其中每个操作都需要一个请求对象并返回一个响应对象。

我意识到这对于许多人来说或多或少是一种标准方法,但是我在问我为什么要打扰?(我对所接受的智慧不是很好,我需要一些理由)。

我将提供的大多数服务是简单的组织元数据检索。例如,找到特定用户的安全策略。这需要一个用户ID,无其他要求。该标准告诉我,我应该将此请求包装在一个对象中,并将返回的策略包装在一个响应对象中。

查看合同产生的WSDL会加剧我的不安。WCF自动生成请求和响应消息,甚至包装请求/响应对象。

我完全理解,如果您要发出复杂的请求,那么就需要一个复杂的输入对象。即使服务不涉及,那也是您要做的。

我的问题是为什么在以下情况下我应该自动包装请求和响应:

  • 它使简单服务的表现力降低
  • 无论如何,您都会为复杂的服务而做
  • WCF无论如何都会创建请求/响应消息

我发现以下论点支持这种方法:

它通过允许将可选参数放入请求对象中来支持版本控制。

过去,我做了很多的COM,我认为这几乎是版本控制的反模式。对于某些事情,我想它会有所帮助,但我希望它会有所帮助,无论如何您已经有一个参数对象。

它允许将常见数据和行为隔离到基类

这个给我带来一些分量。

它使人们远离RPC样式的行为而转向消息传递的行为

我已经在Microsoft网站上阅读了此内容,并从我们的专家那里听到了,但是我仍然不清楚它们的含义或价值所在。看起来自然的界面是否使人们倾向于忘记他们正在调用远程服务?

我正在考虑重构大约300种方法的签名,因此这是不小的痛苦。我非常喜欢实现的一致性,因此我愿意承担痛苦,这将有助于知道最终所有这些都是值得的。

Answers:


3

我认为版本控制可能是最好的论据。当您拥有现有的运营合同时,例如

int GetPersons(int countryId);

您想要增强的功能,例如稍后通过另一个过滤器

int GetPersons(int countryId, int age);

由于它必须是唯一的,因此您必须写一个新的操作合同并使用新名称。或者,您可以保留名称并发布新的服务v2,而旧的v1仍然存在,以便向后兼容。

如果将参数包装到对象中,则始终可以使用默认/可选参数对其进行扩展,并且当您重复使用相同的操作合同时,所有现有客户端都不会受到影响。

但是,我也敦促适当地命名您的对象。即使它只是包装一个int,如果您以int开头IntMessage或类似的名称,您也不会对扩展它有所帮助。您必须PersonFilter从一开始就将其命名,例如,这意味着您必须仔细考虑此服务调用在语义上应作为参数的期望以及因此而应该做的事情。也许(这可能是非常模糊的)将有助于开发正确的服务并维护适当大小的API。

它允许将常见数据和行为隔离到基类

这是要谨慎的事情。继承和数据契约不能很好地结合在一起。它确实可以工作,但是您必须指定所有可能通过网络传递的合同的已知子类型,否则数据合同序列化程序将无法抱怨未知类型。

但是您可以做的(但仍然可能不应该做,但我仍未决定)是在不同服务之间重用相同的消息。如果将数据协定放在单独的dll中,则可以在客户端和服务之间共享该协定,并且在调用期望基本相同消息的不同服务时,无需在类型之间进行转换。例如,您创建一个PersonFilter并将其提交给一个服务以获取人员的过滤器列表,然后提交给另一服务并在客户端上具有相同的对象。但是,我找不到一个很好的实际示例,而且危险始终是,对于使用该合同的所有服务,数据合同的扩展都不够通用。

总体而言,除了版本控制之外,我也无法真正找到这样做的杀手级原因。


我认为我之所以选择
安迪·戴维斯

(对不起,评论界面让我很伤心)感谢您的回答。我认为我之所以对版本控制参数这么细心的原因是,如果添加了新参数,则可能会更改语义。如果(例如,在您的示例中)您只是添加了一个年龄,那么语义可能是用于搜索的,并且您首先要有一个“搜索对象”。
安迪·戴维斯

现在考虑我的安全策略示例。也许我们决定为了正确地提供安全策略,我们不仅需要知道用户,还需要知道他们正在使用的工具。这不仅仅是添加参数,我们还改变了调用的语义。假设我们能够以某种方式为先前版本的调用者提供此信息,我认为对服务合同进行版本化更有意义。这样就可以隔离旧版本的实现,而不必最终将旧语义与新语义混在一起。
安迪·戴维斯

0

我认为,Martin Fowler关于“ 数据传输对象”的注释在这里很合适。

当您使用远程接口(例如Remote Facade(388))时,每次调用都很昂贵。结果,您需要减少呼叫数量,这意味着您需要在每个呼叫中​​传输更多数据。一种方法是使用大量参数。但是,这通常很难进行编程-实际上,对于Java这样的仅返回单个值的语言,这通常是不可能的。

解决方案是创建一个数据传输对象,该对象可以保存呼叫的所有数据。它需要可序列化才能通过连接。通常,在服务器端使用汇编程序在DTO和任何域对象之间传输数据。

同样的要求也适用。至于RPC,以及它为什么不好:

看起来自然的界面是否使人们倾向于忘记他们正在调用远程服务?

我认为这是事实,但不是主要原因。避免使用RPC的另一个原因是,它可以鼓励紧密耦合的客户端和服务。


感谢您的输入,但我认为DTO讨论没有那么重要。调用次数是相同的,如果您查看WSDL,则所有内容都会自动打包到请求和响应对象中。约定是关于可见语义的,即人们应该将其视为请求和响应,而不是远程方法调用。
安迪·戴维斯

您是否愿意详细说明RPC,以鼓励紧密耦合的客户和服务?我看不到这完全影响了服务。对于客户来说,我也没有真正看到任何改变。无论哪种情况,我都让客户端持有一个代理,该代理描述了服务提供的许多操作。在任何情况下,真正实现服务另一端的人都不是客户的业务。
安迪·戴维斯
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.