如何处理实现多个接口的对象的Dtos?

我们在WCF服务接口中使用Dtos,但是当Dto表示的业务对象实现多个接口并且我们想要在这些不同的上下文中返回Dtos并且还能够处理时,它们已经开始遇到问题Dtos在客户端上进行多态化。

例如,假设我们有一个IBusinessObject的接口, IBusinessObject包含几个属性,包含对象关系,对象属性等的详细信息。我有几个实现,这个实现是一个实现IBusinessObjectILinear 。 还有ILinear其他实现,它们也不是业务对象,只是简单的线性事物。

我们的服务有一个获取业务对象的方法。 这将返回一个基础Dto类( BusinessObjectDto ),它声明IBusinessObject的常见部分(关系属性等)和LinearBusinessObjectDto ,它扩展了BusinessObjectDto并添加了关于事物线性方面的额外信息。 这很好,并使客户端能够以一定程度的多态性处理返回的BusinessObjects

我们还想要一种获得线性事物的方法。 这将返回一个基类LinearDto ,其中包含常见的线性详细信息。 简单的线性对象实现扩展了LinearDto ,一切都很好。 但是现在我有一个问题,因为我不能让我的LinearBusinessObjectDtoLinearDtoBusinessObjectDto扩展,因为只支持单inheritance,并且我不能使用接口,因为WCF不知道什么类型然后放入服务WDSL中的合同定义。

所以我开始为我的LinearBusinessObject 2个dtos,一个派生自BusinessObjectDtoLinearBusinessObjectAsBusinessObjectDto ),另一个派生自LinearDto( LinearBusinessObjectAsLinearDto ),然后根据我感兴趣的界面转换每个LinearBusinessObjectAsLinearDto

这似乎会导致许多额外的Dto类(其中我已经有很多),所以我想知道是否有比这更好的解决方案? 或者这只是我们必须忍受的东西?

一位聪明人曾告诉我,面向对象是服务的敌人。

在我看来,这是一个普遍的OO / SOA问题而不是特定的WCF问题:我想到了“赞成组合而不是inheritance”的旧建议。 特别是在服务方面,Polymorphic设计不应该是您在DTO层中所追求的。 您应该避免使用使用inheritance或接口的DTO(除非您动态地序列化/反序列化,否则接口甚至不可能…您无法使用SVCUtil生成具体代理,因为具体类型在生成时是未知的,但是来自我的在.NET客户端中使用ChannelFactories时可以实现内存…我不记得细节了。

通常,在创建DTO / DataContracts时,只在其中定义具体的成员/属性。 您的DTO模型应设计为平坦且跨平台,而不是面向对象。

我想我已经理解了你想说的话所以请原谅我,如果我错过了解释。 基本上,您有以下要通过WCF合同传递的对象:

 class SpecificImplementationOfA : IInterfaceA class SpecificImplementationOfB : IInterfaceB class CombinationOfAAndB : IInterfaceA, IInterfaceB 

您提到您不希望在WCF合同上使用接口,因为您可能返回接口的不同实现。

我的问题是你实际上是否需要返回到客户端的对象的相同实现,你真的需要客户端接收CombinationOfAAndB的实例,或者它可以是具有相同签名的其他东西。 其次,客户是否会返回任何这些对象,如果是,那么上述问题如何适用?

如果对此的答案是客户端和服务无关紧要,您是否可以引入实现相关接口的客户端特定对象并在客户端中注册知识类型(KnownTypes用于反序列化而不是序列化)并让WCF执行映射。

 interface IInterfaceAAndB : IInterfaceA, IInterfaceB interface ISomeWcfContract { IInterfaceA GetA(); IInterfaceB GetB(); IInterfaceAAndB GetAAndB(); } class ClientImplementationOfA : IInterfaceA class ClientImplementationOfB : IInterfaceB class ClientImplementationOfAAndB : IInterfaceAAndB private static IEnumerable GetKnownType() { yield return typeof(ClientImplementationOfA); yield return typeof(ClientImplementationOfB); yield return typeof(ClientImplementationOfAAndB); } 

是的,这确实引入了另一个DTO对象,但它只需要存在于客户端上,这意味着您的整个合同都是在接口上实现的,您可以更改客户端或服务器上不同对象的实现/交换,而不会对其他对象产生任何影响只要合同没有被打破。 如果在正确的情况下正确完成,您甚至可以在不破坏现有客户端的情

WCF提供了一个钩子,用于在接口和inheritance链上定义“已知类型”。 我不确定使用ServiceKnownType属性或KnownType属性是否直接适用于您描述的内容,但绝对值得一看。

这是内部Web服务还是外部托管?

如果这是内部的,请查看“配置服务引用”对话框中的“重用引用程序集中的类型”选项

  1. 在客户端项目中引用您的DTO组件(确保您的DTO在他们自己的组件中)

  2. 为目标WCF服务打开“配置服务引用”对话框

  3. 选中“在引用的程序集中重用类型”复选框

  4. 选择“在指定的引用程序集中重用类型”单选按钮

  5. 从列表中选择DTO组件。

ServiceClient()收到的结果将是引用的DTO程序集中的实际类型,而不是生成的代理。 你现在应该能够多态地对你的对象采取行动。

也许你可以封装基础对象。 因此,您拥有BusinessObjectDto和LinearDto对象。 然后,让您的LinearBusinessObjectDto包含两个属性,一个是BusinessObjectDto类型,另一个是LinearObjectDto类型。 当service方法返回一个LinearBusinessObjectD时,它会初始化每个属性。 然后,您可以在LinearBusinessObjectDto上实现接口,并删除对每个属性的调用。 不幸的是,在客户端上,您可以转换为所需的界面,但您应该能够选择要使用的属性。

编辑:不确定DTO部分的接口…不知道是否将在具有接口的客户端上创建实现接口的DataContract属性类??!?

请阅读以下post

http://social.msdn.microsoft.com/Forums/eu/wcf/thread/31102bd8-0a1a-44f8-b183-62926390b3c3

这可能很有用

我正在复制代码供您参考

 [ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")] public interface IServer { [OperationContract] [ServiceKnownType(typeof(EntityInfo))] IEntityInfo GetEntityInfo(string className); } 

你为什么不用组合而不是inheritance呢? 如果不这样,PostSharp多重inheritance会有帮助吗?