2010-02-17 64 views
6

我发现自己负责继续开发一个我原本没有设计的系统,并且不能要求原始设计师为什么采取某些设计决策,因为他们不在这里。我是一名设计问题的初级开发人员,因此在开始执行我的第一个SOA/WCF项目的项目时,并不知道该问什么。SOA和WCF设计问题:这是一个不寻常的系统设计吗?

该系统有7个WCF服务,将增长到9个,每个自我托管在一个单独的控制台应用程序/ Windows服务。所有这些都是单实例和单线程的。所有服务都具有相同的OperationContract:它们公开Register()和Send()方法。当客户端服务想要连接到另一个服务时,他们首先调用Register(),然后如果成功,他们会执行全部与Send()的其余通信。我们有一个DataContract,它具有一个枚举MessageType和一个可以包含其他DataContract“有效内容”的Content propety。这个服务对消息的处理是由枚举MessageType决定的......一切都是通过Send()方法来实现的,然后被路由到一个switch语句......我怀疑这是不寻常的

Register()和Send( )实际上是OneWay和Async ...服务的所有结果都通过WCF CallbackContract返回给客户端服务。我相信使用CallbackContracts的共同点是促进我们正在使用的发布 - 订阅模型。问题不在于我们所有的沟通都适合发布 - 订阅,而使用CallbackContracts意味着我们必须在返回的结果消息中包含源细节,以便客户端可以计算出返回的结果最初是用于什么......再次,客户端有一个switch语句可以制定出来如何处理基于MessageType的服务(以及其他嵌入的详细信息)。

就拓扑而言:服务在图形中形成“节点”。每个服务都有一个硬件编码列表,当它启动时它必须连接到其他服务列表,并且不允许客户端服务“注册”它,直到完成所有需要的连接。作为一个例子,我们有一个LoggingService和一个DataAccessService。 DataAccessSevice是LoggingService的客户端,因此DataAccess服务将在启动时尝试向LoggingService注册。直到它可以成功注册DataAccess服务将不允许任何客户端注册它。结果是,当整个系统启动时,服务以级联的方式启动。我不认为这是一个问题,但这是不寻常的?

为了使事情更复杂,其中一个系统要求是服务或“节点”不需要直接相互注册,以便将消息发送给另一个,但可以通过间接链接进行通信。例如,假设我们有3个服务A,B和C连接在一个链中,A可以通过 B ...使用2个跳来发送消息给C

我的确负责编写路由系统,这非常有趣,但是在我问到为什么真的需要它之前,我已经离开了领导层。据我所知,服务不能直接连接到他们需要的其他服务是没有道理的。除此之外,我还需要编写一个可靠性系统,因为要求在系统中具有可靠的消息节点,通过简单的点对点链接WCF可靠地完成这项工作。

在此项目之前,我只在winforms桌面应用上工作了3年,不知道更好。我的怀疑是这个项目过于复杂的事情:我想总结一下,我的问题是:

1)这种思想的图形拓扑消息跳过间接链接异常?为什么不直接将服务直接连接到他们需要访问的服务(实际上我们是这样做的......我不认为我们有任何消息跳跃)?

2)在OperationContract中只公开了2个方法,并使用MessageType枚举来确定消息的用途/用它做些什么异常?不应该有一个WCF服务暴露了许多具有特定目的的方法,而客户端选择了它想调用的方法?

3)正在通过CallbackContracts与客户进行所有通信。当然,同步或异步请求响应更简单。

4)服务是否允许客户端服务连接到它(注册),直到它连接到它的所有服务(它是客户端)为止的声音设计?我认为这是我同意的唯一设计方面,我的意思是DataAccessService在与日志服务连接之前不应该接受客户端。

我有太多的WCF问题,以后会有更多的问题。提前致谢。

回答

6

那么,整个事情似乎有点奇怪,同意。

所有这些都是单实例,并且单线程为 。

这绝对会回来,并导致巨大的性能头痛 - 保证。我不明白为什么有人希望编写一个单独的WCF服务(除了几个边缘情况,它的确有意义),并且如果你有一个单独的WCF服务,为了获得任何体面的性能,必须是多线程的(这是棘手的编程问题,也是我几乎总是提出反对的原因)。

所有服务具有相同的 OperationContract的:他们暴露 注册()和send()方法。

这也很奇怪。所以任何人都会先调用.Register(),然后用不同的参数调用.Send()几次?有趣的设计,真的...... SOA的假设是你设计你的服务是你想要向外界展示的一组功能的模型,例如,你的CustomerService可能有像GetCustomerByID,GetAllCustomersByCountry等方法 - 取决于你需要什么。

只有一个带参数的Send()方法可以定义正在做什么,看起来有点......不常见,并且不太直观/清晰。

这是一个图形拓扑结构的想法, 消息跳过间接链接 异常吗?

不一定。只向外界公开一个接口是有意义的,然后使用一些内部后端服务来完成实际的工作。 .NET 4实际上会引入一个RoutingService in WCF,这使得这些场景更加容易。我不认为这是一个很大的禁忌。

正在通过CallbackContracts异常地将所有通信回传给 客户端。

是的,不寻常的,脆弱的,凌乱的 - 如果你能做到没有它 - 去为它。如果您主要是通过简单的方式拨打电话,如GetCustomerByID - 使这些为标准的请求/响应呼叫 - 客户端请求(通过提供客户ID)并获取返回值作为返回值。简单得多!

如果您确实有长时间运行的服务调用,那可能需要几分钟或更长时间才能完成 - 那么您可能会考虑将请求存入队列的单向调用,并且稍后会处理该请求。通常,在这里,您可以将答案存入客户端随后检查的响应队列中,或者您可以有两种额外的服务方法给您请求的状态(是否已完成?),第二种方法是检索该请求的结果。

希望能帮助你开始!

+0

Send()方法接受一个ActionMessage DataContract,它具有用于路由到目标的字符串Destination字段,以及对另一个DataContract类型的引用作为有效内容。有效载荷DataContracts全部从具有MessageContentType枚举字段的基本类型继承,正是这种服务用于确定它们是否对通过它们的数据处理感兴趣,然后才将它们路由到该消息。目标字符串可以指定您希望消息通过的服务节点类型。 感谢您的信息。在其他一些答复之后,我将其标记为答案。 – MrLane 2010-02-17 06:52:02

+0

我应该补充一点,我们确实有一个SessionManagerService,它是我们的Silverlight客户端系统的“网关”。最初他们确实通过这个网关(使用它的Send()方法)向后端服务发送消息,该消息将消息路由到正确的后端服务,并将消息路由回到来自这些服务的正确浏览器客户端实例。然而,现在,情况并非如此,在客户端<> SessionManager <> BackEndServices之间使用了单独的消息,因此eveything是单跳。 SessionManager实际上保留了UI状态并将其“推送”给Silverlight客户端。 – MrLane 2010-02-17 07:08:16

5

所有服务都具有相同的OperationContract:它们公开Register()和Send()方法。

您的设计在某些部分显得不寻常,特别是只暴露了两个操作。我没有使用过WCF,我们使用Java。但基于我的理解,Web服务的全部目的是揭露您的合作伙伴可以使用的操作。
只有两个操作看起来像奇怪的设计给我。您通常使用WSDL公开您的API。在这种情况下,除非您有大量文档,否则WSDL不会为合作伙伴增加任何价值。通常操作名称应该是不言自明的。现在,如果没有内部知识,您的系统不能被合作伙伴使用。

正在通过CallbackContracts与客户端进行所有通信。当然,同步或异步请求响应更简单。

同意你的意见。异步只能用于长时间运行的进程。异步增加了相关性的开销。