我正在编写客户端/服务器应用程序,其中客户端是Windows窗体应用程序,服务器是Windows服务中托管的WCF服务。请注意,我控制应用程序的两面。
我正在尝试实现对接口进行编码的做法:即我有一个由客户端应用程序引用的共享程序集。该项目包含将向客户端公开的WCF ServiceContracts和接口。我试图只向客户端公开接口,这样它们只依赖于契约,而不是任何特定的实现。这样做的原因之一是,我可以随时进行服务实现和域更改,而无需重新编译和重新部署客户端。在这种情况下,接口/合同不会改变。我只需要重新编译和重新部署我的WCF服务。
我现在面临的设计问题是:在客户端上,如何创建对象的新实例,例如ICustomer
,如果客户端不知道Customer
具体实现?我需要创建一个新客户以保存到数据库中。
我是使用依赖注入还是Factory类来实例化新对象,还是应该让客户端创建具体实现的新实例?
我没有做TDD,我通常只有一个ICustomer
或任何其他公开接口的实现。
答案 0 :(得分:1)
我们已经讨论过为企业应用程序内部执行此操作,我们控制应用程序的两个方面,作为.NET客户端的生产力增益。陪审团仍在这个问题上。
但是,在讨论在共享库中(在客户端和服务之间)签订合同时,通常会包括 服务合同([ServiceContract]),以及实体([DataContract])用于服务操作的任何参数。这些类型传统上是您期望进行这些服务操作的具体类型。
在您的情况下,您的DTO实现了一个接口,例如ICustomer,实现了代表Customer的属性,并且是[DataContract]。假设该类型将正确地序列化到服务(使用NetDataContractSerializer),那么我想客户端几乎可以推动他们想要的具体实现 - 该服务只对符合ICustomer的内容感兴趣。
客户端可以创建他们想要的任何具体的ICustomer实例:OrderingCustomer,FinanceCustomer等。只要该类型实现了服务ICustomer接口,如果它序列化,可以想象它作为值传递给服务操作正确地即可。例如
public class OrderingCustomer : ICustomer
{
}
我不确定您的目标是否会实现零客户端影响。如果更改接口类型(将属性添加到ICustomer),则客户端将需要重新编译。如果添加参数,即使是核心.NET类型(例如int)之一,您的客户端也需要重新编译。这实际上与客户端更新其服务引用和重新编译的影响相同。
但是,如果不更改服务实施或行为(例如错误修复),那么在两个情况下(共享类型或服务引用),客户端将不需要只要您和您的客户之间的合同没有变化,我就会做任何事情。当然,我也希望听到你对此有任何经验证明这是错误的!
这种做法也会完全扼杀非.NET系统的可互操作故事。当我把它扫到地毯下时,有些部门会听到你的超级漂亮的服务并想要使用它......他们将运行一些Java堆栈,或COBOL,或FORTRAN..etc。 :)
答案 1 :(得分:1)
我在WCF开发中遇到过同样的问题。事实是必须在通信的双方上具体实施您的数据合同。那么这些实现来自哪里?在服务器端,实现通常是您的业务对象,具有所有业务逻辑等。并且您不希望在客户端上使用这些实现 - 这意味着将它们放在共享程序集中,并且由于多种原因您不希望这样做。所以客户需要自己独立的具体类。要么你自己要写,要么自动生成它们。
自己编写实现是乏味的。因为客户端对象通常很简单 - 他们真正做的就是存储数据 - 代码生成可能就是这样。此时您有几个选择:您可以通过添加服务引用基于WSDL生成代码,或者您可以使用某种框架基于接口在运行时生成类。
这两种方法都为您提供了对接口进行编码的好处:只要接口不发生变化,就可以独立修改和重建服务器和客户端。在一种情况下,接口是WSDL,而在另一种情况下,它是一个CLR接口,但由于WCF基于CLR接口生成WSDL,它们实际上是同一个。我个人喜欢添加服务参考,因为它已经存在并且没有为我的项目添加任何依赖项,但是选择你想要的更好。
答案 2 :(得分:0)
嗯,我认为你混淆(或混淆)了两件事:
您的服务合同将仅描述您的服务公开的功能,例如FindCustomer
或AddCustomer
- 对于这些操作,您的客户只需要知道接口,当您添加客户端代理(通过使用“添加服务引用”)时,您还将在客户端代理中获得一个YourServiceClient
具体类来实现这些调用
数据合同描述来回传输的数据,这些数据总是具体的类 - Customer
,Invoice
等等 - 因为这些是基于XML模式。这些是在服务器上定义的,客户端在添加服务引用时,将从服务发布的WSDL / XSD中推断出这些类型,并将在客户端为此数据创建具体类 。那些 NOT 与服务器使用的完全相同的类 - 它们看起来是一样的,它们的主要要求是它们从XML序列化和反序列化 - 但它们实际上是不同的类(不同。 NET命名空间,最有可能)。
因此,对于您的功能,您拥有的服务合同实际上只需要作为接口共享 - 这就足够了,客户端将从该接口创建一个“代理类”(YourServiceClient
类)。客户端不依赖于服务器实现或其具体类。
另一方面,交换的数据 - 默认情况下被序列化为XML格式 - 将始终是从WSDL / XSD中获取的具体类(无接口) - 同样,客户端不依赖于服务器的类 - 只有他们的“XML序列化指纹”,可以这么说。
现在我不确定这对你有多大帮助:-)但至少它有希望让事情变得更清楚 - 或者不是吗?
马克
答案 3 :(得分: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
HTH
夏兰