从客户端向WCF服务发送查询

3
我希望你能就以下问题给出你的看法。
我们正在考虑使用SOA作为解决方案来解决一些概念上的问题。我们不想重复构建相同的逻辑,所以想要创建一些WCF服务,并让不同的客户端通过这些服务检索数据(甚至是苹果应用程序)。理想情况是客户端尽可能地轻巧,只关心展示。所有的业务逻辑和数据访问都应该在WCF服务中进行处理。
现在我的老板研究了这个问题,他最大的担忧基本上是我们会陷入混乱。他认为我们将为每个要执行的数据库查询定义一个新方法,粗略地说。
例如:
RetrieveCustomerById RetrieveCustomerByName RetrieveCustomerByStoreId RetrieveCustomerWithPersonalDetailsButWithoutAddressById 等等……
因此,他的想法是让客户端构建查询并将其发送到WCF服务。WCF服务执行查询,应用业务逻辑并返回结果。
我非常感兴趣你们能想到的所有优点和缺点。预先感谢你们的思考。
4个回答

1
这是一个SOAP风格的WCF服务吗?还是RESTful的?
无论哪种方式,我都会倾向于设置一组可选参数,通过这些参数可以进行请求。以RESTful服务为例,您可以有一组额外的查询字符串参数来检索客户端。

e.g.:

/Customers?id=ID /Customers?name=NAME /Customers?StoreId=STORE /Customers?id=ID&withPersonalDetails=true&withPersonalDetails=false

当然,如果您主要通过ID获取,则

/Customers/{id}/

将是一个好的服务URL。

等效的内容也适用于SOAPy端,请求中有一堆可空参数。

优点是客户端只需要知道它所知道的客户信息,并且可以将其提供给服务,服务可以在检索客户之前处理更复杂的任务,以确定查询需要什么。缺点是客户端可能会构造未提供足够信息以获取客户的请求。

但至少您不必担心客户端提供无效的查询。

编辑:

关于为什么让客户端提供查询是一个糟糕的想法——简单回答就是“它会破坏封装性,并且会引入大量的耦合”。长期的答案是,现在客户端依赖于服务实现细节。假设数据库的布局发生变化,理想情况下您希望更改尽可能少的内容,在一个很好的封装系统中,您只需要更新持久层,可能不需要更新其他任何内容。如果您的客户端需要理解模式,则必须一直更新所有层次,这显然是不好的。
第二,如果客户端提供查询,那么您就会将隐式信任客户端——您需要做出巨大的努力来限制客户端的行为——请考虑一下,如果有人开始冒充您的客户端并对您的数据库运行任意查询,那将会发生什么呢?
第三,如果您需要修复一个查询,如果查询在客户端上,您必须更新客户端代码并向所有客户端推送更新(某些用户可能无法接受更新,留下了这些用户的错误),如果查询封装在服务中,则只需在该服务处修复问题即可。

第四,你的业务规则现在在哪里执行?在客户端。通过在客户端和数据库之间使用服务,所有的业务规则都在一个地方,你可以很好地控制。

如果你的客户端正在编写数据库查询,那么它可能直接连接到数据库,这在许多情况下是可以的。但是,如果你想要能够在服务后面抽象数据库访问、在一个地方更新/修复你的业务规则,并限制恶意客户端对你的责任,那么这是一个非常糟糕的想法。

(我相信还有其他几十个原因,在喝上午茶之前,这些是我脑海中的一些。)


1
如果这是一个SOAP服务,您可以使用单个参数来接收“SearchParameters”对象,其中整个搜索被很好地定义。 - Tridus
@Massif: <br/> 首先感谢您的回复,但很抱歉。无论是SOAP还是RESTful都不重要。请看我的回复Aliostad。让我更清楚地为您阐述问题。我的老板想要做这样的事情:/Customers?query="SELECT * FROM Customer WHERE ID = 1"这在许多层面上都违反了常规实践,但我们想知道为什么不能这样做。所以你认为为什么我们不应该这样做?@Tridus: <br/> 和Massif一样,对您也是一样的情况。感谢您的回复。请查看我写给Aliostad和Massif的内容。 - user655382

1

你的老板可能是对的,这大概就是它看起来的样子,但是:

  • 首先,有什么必要错误的(尽管读到最后有些不合理)?
  • 不会有RetrieveCustomerWithPersonalDetailsButWithoutAddressById,因为CustomerWithPersonalDetailsButWithoutAddress是一个不同的领域模型。
  • 将查询传递给业务逻辑非常像旧时代,在接口中参数被定义为object(或者如果你和我一样老,那就是VB6 COM中的Variant)。这意味着我们不想花费精力和挑战去理解我们的领域
  • RetrieveCustomerByStoreId将不再需要,因为如果它与商店有关,则商店存储库有责任提供它。

总之,如果你遵循DDD,传递查询只会使设计变得非常松散。


我的老板来自“Variant VB6 COM”时代。他甚至争论为什么我们应该有三层架构。他说这会使修复问题的时间变长三倍。而我当然持相反观点。现在你明白他为什么想在客户端构建查询,将它们传递给服务。服务执行提供的查询,应用一些逻辑并发送数据回来。我真的需要和我的老板回到基础知识。简单地说,我们会破坏DDD并不是他认可的论点。忘记你所知道的关于编程的一切。现在告诉我为什么我们不应该将SQL查询(作为字符串)作为参数提供给服务。 - user655382

1

@Jean-Christophe Fortin: <br/> 是的,我有。但是数据库还没有为Entity Framework做好准备(我发现WCF数据服务与EF结合使用最有用),此外我们还希望在服务器端拥有业务逻辑。 - user655382

0
所以他的想法是让客户端构建查询并将其发送到WCF服务。WCF服务执行查询,应用业务逻辑并返回结果。
这被称为规范模式,在DDD中经常使用。
一个接受规范参数的服务方法足以处理95%的对象请求。 WCF RIA Services中的EntityQuery类就是一个例子,展示了规范模式如何在客户端-服务端架构中使用。

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