1

我正在编写一个客户端/服务器应用程序,其中客户端是 Windows 窗体应用程序,服务器是托管在 Windows 服务中的 WCF 服务。请注意,我控制应用程序的双方。

我正在尝试实现针对接口进行编码的实践:即我有一个由客户端应用程序引用的共享程序集。这个项目包含我的 WCF ServiceContracts 和接口,它们将暴露给客户。我试图只向客户端公开接口,以便它们只依赖于合同,而不是任何特定的实现。这样做的原因之一是我可以随时进行服务实现和域更改,而无需重新编译和重新部署客户端。在这种情况下,接口/合同不会改变。我只需要重新编译和重新部署我的 WCF 服务。

我现在面临的设计问题是:在客户端,我如何创建对象的新实例,例如ICustomer,如果客户端不知道Customer具体的实现?我需要创建一个新客户以保存到数据库中。

我是使用依赖注入,还是使用工厂类来实例化新对象,还是应该只允许客户端创建具体实现的新实例?

我不做 TDD,我通常只有一个实现ICustomer或任何其他公开的接口。

4

4 回答 4

1

我在 WCF 开发中遇到了同样的问题。事实上,必须在通信双方都有具体的数据合同实施。那么这些实现是从哪里来的呢?在服务器端,实现通常是您的业务对象,以及它们的所有业务逻辑等等。而且您不想在客户端上使用这些实现——这意味着将它们放在共享程序集中,并且您不希望这样做有几个原因。所以客户端需要它自己的、单独的一组具体类。您要么自己编写它们,要么让它们自动生成。

自己编写实现很乏味。因为客户端对象通常很简单——它们真正做的只是存储数据——代码生成可能是要走的路。此时您有几个选择:您可以通过添加服务引用基于 WSDL 生成代码,或者您可以在运行时使用某种框架基于接口生成类。

这两种方法都为您提供了针对接口进行编码的好处:只要接口不改变,服务器和客户端就可以独立修改和重建。在一种情况下,接口是 WSDL,在另一种情况下,它是 CLR 接口,但由于 WCF 基于 CLR 接口生成 WSDL,所以它们实际上是一回事。就我个人而言,我喜欢添加服务引用,因为它已经存在并且不会向我的项目添加任何依赖项,而是选择你更喜欢的那个。

于 2010-01-14T15:13:34.940 回答
1

我们已经讨论过在内部为我们控制应用程序双方的企业应用程序执行此操作,以提高 .NET 客户端的生产力。陪审团仍在这个问题上。

但是,当讨论在共享库中(在客户端和服务之间)拥有合同时,通常这将包括服务 合同([ServiceContract])以及服务操作的任何参数的实体([DataContract])。这些类型通常是您期望的那些服务操作的具体类型。

在您的情况下,您的 DTO 实现了一个接口,例如 ICustomer,实现了代表客户的属性,并且是一个 [DataContract]。假设类型将正确序列化到服务(使用 NetDataContractSerializer),那么我想客户端几乎可以推动他们想要的任何具体实现——服务只对符合 ICustomer 的内容感兴趣。

客户端可以创建他们想要的任何具体的 ICustomer 实例:OrderingCustomer、FinanceCustomer 等。 只要该类型实现了服务 ICustomer 接口,如果它正确序列化,它就可以作为值传递给服务操作。例如

public class OrderingCustomer : ICustomer
{
}

我不确定您是否会实现零客户影响您的目标。如果您更改接口类型(向 ICustomer 添加属性),您的客户端将需要重新编译。如果您添加一个参数,即使是核心 .NET 类型之一(例如 int),您的客户端也需要重新编译。这实际上与客户端更新其服务引用和重新编译的影响相同。

但是,如果您更改您的服务实现或行为(例如错误修复),那么在这两种情况下(共享类型或服务引​​用),只要您和您的客户之间的合同没有改变,客户就不需要做任何事情。当然,我也想听听你有什么经验证明这是错误的!

这种做法也将彻底扼杀您与非 .NET 系统的互操作故事。可以肯定的是,当我把它扫到地毯下时,某个地方的某个部门会听说你的超级漂亮的服务并想要使用它……他们将运行一些 Java 堆栈、COBOL 或 FORTRAN ……等等。:)

于 2009-08-17T12:31:31.630 回答
0

好吧,我认为您混淆(或混淆)了两件事:

  • 您的服务合同将仅描述您的服务公开的功能,例如FindCustomerAddCustomer- 对于这些操作,您的客户端只需要知道接口,并且当您添加客户端代理(通过使用“添加服务引用”)时,您还将在您的客户端代理中获取一个YourServiceClient实现这些调用的具体类

  • 数据契约描述了来回传输的数据,并且那些总是具体的类——等等Customer——Invoice因为它们是基于 XML 模式的。这些是在服务器上定义的,客户端在添加服务引用时,将从服务发布的 WSDL/XSD 中推断出这些类型,并将在客户端为这些数据创建具体的类。这些与服务器使用的类并不完全相同——它们看起来相同,并且它们的主要要求是它们序列化和反序列化 XML 相同——但它们实际上是不同的类(很可能是不同的 .NET 命名空间)。

因此,对于您的功能,您拥有真正只需要作为接口共享的服务合同——这就足够了,客户端将从 YourServiceClient该接口创建一个“代理类”(类)。客户端不依赖于服务器实现或其具体类。

另一方面,正在交换的数据 - 默认情况下被序列化为 XML 格式 - 将始终是从 WSDL/XSD 推断出的具体类(无接口) - 同样,客户端不依赖于服务器的类 - 仅在他们的“XML序列化指纹”,可以这么说。

现在我不确定这对你有多大帮助:-)但至少它希望能让事情变得更清晰——或者不是?

马克

于 2009-08-14T13:51:18.367 回答
0

您现在可能已经得到了答案,但我目前正在尝试做类似的事情 - 将我的存储库注入到我的 WCF 服务中,因此这些服务对访问数据库的代码没有任何依赖关系。我发现以下文章可能有助于回答您的问题:

http://geekswithblogs.net/ballhaus/archive/2009/12/12/unit-testing-your-wcf-service.aspx http://www.silverlightshow.net/items/Deep-dive-into-WCF-part -1-TDD.aspx

高温高压

夏兰

于 2010-03-30T23:11:42.870 回答