2009-08-14 34 views
1

我正在编写客户端/服务器应用程序,其中客户端是Windows窗体应用程序,服务器是Windows服务中托管的WCF服务。请注意,我控制应用程序的两侧。在针对接口进行编码时,工厂或WCF中的对象实例的依赖注入?

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

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

我是否使用依赖注入或Factory类来实例化新对象,还是应该让客户端创建具体实现的新实例?

我不是在做TDD,我通常只会有一个实现ICustomer或任何其他暴露的接口。

回答

0

嗯,我想你混淆(或混淆)两件事情:

  • 服务合同将只描述你的服务公开的功能,像FindCustomerAddCustomer - 为那些行动,客户端只需要知道的接口,当你添加一个客户端代理(通过使用“添加服务引用”),你还可以得到一个YourServiceClient具体类中实现这些调用您的客户端代理

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

因此,对于你的功能,您有服务合同,你真的只需要共享一个接口 - 这是足够的,并且客户端会从该接口创建一个“代理类”(即YourServiceClient类)。客户端不依赖于服务器实现或其具体的类。另一方面,被交换的数据 - 默认情况下被序列化为XML格式 - 将始终是从WSDL/XSD中传递的具体类(无接口) - 再次,客户端不依赖于服务器的类 - 只能在他们的“XML序列化指纹”上,可以这么说。

现在我不确定这可以帮助你很多:-)但至少它有希望让事情变得更清楚一点 - 或者没有。

马克

+0

@marc_s:我觉得你完全误解我的问题。我想我应该修改它以使其更清晰。我完全理解WCF,以及你所解释的一切。但我没有这样使用WCF。客户端和服务器共享MyProject.Shared程序集,其中包含我的类型和接口(或我将称之为合同,但不包含[DataContract])。因此他们从同一个装配中共享完全相同的类型。我现在用的是NetDataContractSerializer,并使用WCF模仿更接近于 – 2009-08-14 14:14:07

1

我们已经讨论了在内部做这行,我们控制应用程序的两侧企业应用,为生产力的提高,为.NET客户端。陪审团仍然在这一个。

然而,在讨论具有一个共享库合同(客户端和服务之间)时通常,这将包括服务合同([的ServiceContract]),以及作为用于实体([DataContract])任何参数服务操作。这些类型传统上是您期望用于这些服务操作的类型混凝土

就你而言,你的DTO实现了一个接口,比如ICustomer,实现代表Customer的属性,并且是[DataContract]。假设类型将正确地序列化到服务(使用NetDataContractSerializer),那么我想客户端可以提供他们想要的任何具体实现 - 服务只关心符合ICustomer的服务。

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

public class OrderingCustomer : ICustomer 
{ 
} 

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

但是,如果你的改变你的服务实现或行为(例如bug修复),然后在两种案件(共享类型或服务引​​用)的客户将需要花费很长时间没有做任何事情,你之间的合同而你的客户不会改变。当然,我也想听听你用这个证明这个错误的经验。

这种做法也将彻底杀死您与非.NET系统的互操作故事。就像我在地毯下扫描这个东西一样,某处的某个部门会听到你的超级服务并希望使用它......而且他们将运行一些Java堆栈,COBOL或FORTRAN ..等等。 :)

+0

你形容我试图实现精确.Net远程,但你还没有回答我的问题 - 如何在客户端上创建对象的新实例侧。你显然不能做到这一点:'ICustomer CUS =新ICustomer',你不能做到这一点无论:'ICustomer CUS =新客户()'因为客户端不能够访问包含了'客户大会:客户“实施。 – 2009-08-17 13:11:50

+0

啊,我想我错过了我的回应中的一点!这就是我读得太快了! :)如果客户是服务操作的参数,则客户必须有权访问ICustomer。否则,他们将如何调用该服务?他们不会知道ICustomer是什么样的 - 他们不能仅仅在飞行中完成它,它是客户和服务之间的二元契约。客户不能创建自己的ICustomer实现并使用它,你必须提供它。 :) – 2009-08-17 13:38:15

+0

你又错过了一个关键点。客户端可以访问'ICustomer',它位于共享程序集中,由客户端和服务器引用。必须的!但是'ICustomer'是一个接口 - 并且不能实例化接口类型,如上所述。 – 2009-08-17 16:44:43

1

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

编写你自己的实现是单调乏味的。因为客户端对象通常很简单 - 他们真正要做的就是存储数据 - 代码生成可能是一种方式。在这一点上,您有几个选择:您可以通过添加服务引用生成基于WSDL的代码,也可以使用某种类型的框架基于接口在运行时生成类。

这两种方法给你的编码对接口的好处:只要接口不发生变化,服务器和客户端可以修改和独立重建。在一种情况下,接口是WSDL,另一种是CLR接口,但是由于WCF基于CLR接口生成WSDL,它们确实是一样的。就我个人而言,我喜欢添加服务引用,因为它已经存在,并且不会为我的项目添加任何依赖关系,但可以选择更适合您的项目。