我们正在使用WCF实现Request/Response Service Layer,其中每个请求都从基本Request类继承,并且每个响应都从基本Response类继承。
该服务有一个Process方法,它接受一个Request并返回一个Response。
// Messages contract
public abstract class Request {}
public abstract class Response {}
// Operation contract
Response Process(Request request);
然而,我们团队的某些成员认为,不是期望并返回单个请求/响应的操作合同,而是应该接受并返回一系列请求/响应。
// Operation contract
Response[] Process(Request[] requests);
就个人而言,我没有在语义上发现它是正确的,并且在需要一次处理相关请求的集合(可能是批处理)的情况下,会考虑引入BatchRequest和BatchResponse消息。
public class BatchRequest : Request
{
public Request[] Requests {get;set;}
}
public class BatchResponses : Response
{
public string BatchReference {get; set;} // for example
public Response[] Responses {get;set;}
}
对我来说接受并返回一个数组看起来似乎不正确,这肯定是我在任何地方都没见过的模式。这有什么不对吗?如果是,那是什么?
有些人认为接受/返回数组会让我们没有引入批处理请求的额外复杂性(如上图所示),并且无论如何都可以在数组中发送单个请求。
由于
答案 0 :(得分:14)
首先,数组增加了不必要的复杂性。保持简单(和)愚蠢。
例如。如何处理错误?如果请求#1失败,请问#2和#3是否仍然执行?如何报告错误?
您的同事希望通过制作所有请求数组来解决哪些问题?如果它的性能,它闻起来像过早的优化。还有其他几种方法可以提高性能,但在真正需要之前不要做任何事情。
如果要释放客户端而不是等待结果,请切换到异步客户端。
答案 1 :(得分:8)
我更喜欢单个请求和响应,并使用命令模式批处理要执行的多个操作。
我发现SOA足够复杂,没有出现意外的模式。如果部分请求失败,它们全部回滚,还是仅失败的请求会发生什么? Aaarghhh,我的头开始疼。
答案 2 :(得分:4)
IMO,您决定设计/建模这些服务应该完全基于其使用场景。
在SOA建模期间 - 目标应该是构建松散耦合的系统/服务 - 支持相关的业务领域(应用程序)。
理想情况下 - 您的服务不应过于细化,也不应太复杂。它的重用同样重要。由于这个原因 - 您需要考虑客户需要什么。
以下是一些可能有用的方案
信息即服务
通过公共服务访问数据(主数据)。 - 在这种情况下,以批处理模式访问主数据实际上没有意义。
更新群组数据 - 将用户迁移到新销售计划的服务?(!)
并且,我不认为使用数组处理错误情况是一个问题 - 你真的无法概括问题 - 它的上下文。这是一个设计决定。
与上面的情况[2]一样 - 您可以处理所有内容并在Response []中返回错误代码。
答案 3 :(得分:1)
作为一个概念,批量请求似乎确实有意义 - 我过去为某些服务引入了这样的模式,以减少“烦躁”。似乎有两个响应概念:我是否理解批处理作为一个整体以及批处理中每个成员的响应是什么。因此,它不仅仅是一个简单的响应数组。
我还会考虑延迟执行批处理成员的可能性。因此,第一个响应是“我理解您的批处理”与一些其他服务,以获取单个批处理成员的状态,或一些异步响应传递机制。
摘要:您将需要单独的请求/响应,批处理功能可能很有用,并且可以进行相当程度的扩展。
答案 4 :(得分:1)
提出批量请求的人总是在考虑接口性能。那是件好事。问题不应该是“我们应该批量请求吗?”而是“我们能否在整个界面上实现可接受的性能?”。我曾经使用过在LAN上表现良好的接口(例如,办公室内10Mb以太网),但在跨大西洋链路上运行速度很慢,跨越跨太平洋链路就失败了。我想到的示例将接口更多地视为RPC层而不是“业务操作”层,并且它在网络跟踪中显示。
jgauffin清楚地敲击了指甲 - 单个请求的失败对批次意味着什么?操作是否为有序列表,以便不必尝试后续操作?它们只是一组,为传输而分组,还有其他不相关的?它们是复合事务,以便先前成功的操作应该回滚吗?
API构建是一门艺术,而不是一门科学,也许是一门黑人艺术。用Prester Potter Stewart的话来解释,
“我今天不会再进一步尝试 定义我的材料种类 理解被接受[好 API设计];也许我永远不会 成功地理解这一点。但 当我看到它时,我就知道了。“
答案 5 :(得分:1)
您正在考虑的是我所谓的分层 - 在复杂协议之上实施简单协议。这完全是完全错误的。像您所想的那样的请求/响应已经存在,它被称为HTTP。
也就是说,即使您不想使用REST服务,也不应该这样做。如果由于合同更新而导致调用服务时遇到问题,那么您做错了。一个解决方案,如果您被迫使用WCF而不是像nServiceBus或MassTransit或任何其他ESB框架那样更好的东西可能如下所示:
答案 6 :(得分:0)
根据我的经验,您开始使用单个请求/响应模式,然后稍后公开单独的BatchRequest / BatchResponse模式(具有请求/响应数组)的方法是短期和长期的最佳方法为您的API。
暴露的初始API模式应该是单个请求和响应,仅仅是为了具有易于理解的接口。简单的界面使API的模式(它的方法和对象)易于学习,这对于用户采用非常重要。您的用户将首先了解API并尝试启动并运行该服务,因此会非常欣赏它的简单性。强制用户在初始API中构建请求数组将不会被理解,并且会使API复杂化,并且会对同事进行过早优化。
但是,您的同事之所以正确,您的用户最终会想要的是批处理请求和响应的选项,因为他们对API更加熟悉。正如您所建议的那样,通过实施单独的BatchRequest / BatchResponse模式,您的同事关注最佳。实现单独的BatchRequest / BatchResponse模式很常见,它可以在构建于单例请求/响应模式的实现之上并重用大部分代码的方式完成。要明确的是,我们的想法是您从之前批量处理单个请求。根据我的经验,您的API必须以不必要且毫无根据的方式启动并绑定到请求/响应数组模式。
现在,由于我不知道你的同事的用例是什么,我将猜测为什么他们想要从一开始就使用数组。如果您的同事需要数组请求,因为他们担心对多个对象执行多个CRUD操作,那么解决方案不是要有多个请求,而是要将单个请求绑定到单个CRUD操作类型,并让请求获取批量执行操作的对象数组。您不希望强制用户对每个对象执行单独的请求,因为这肯定不会扩展。批处理最好被认为是一种高级API技术,仅在理解API的基本模式以及用户希望扩展其应用程序时使用。
即,首先公开单个请求/响应模式,然后公开可选的batchrequest / batchresponse模式。使用它构建单个请求/响应模式,最终这些请求将被批处理。