我们在WCF服务接口中使用Dtos,但是当Dto表示的业务对象实现多个接口并且我们想要在这些不同的上下文中返回Dtos并且也能够在客户端上以多态方式处理Dtos。
例如,假设我们有一个IBusinessObject
的接口,其中包含几个属性,包含对象关系,对象属性等的详细信息。我有几个实现这个是{{1}实现LinearBusinessObject
和IBusinessObject
的方法。还有ILinear
的其他实现,它们也不是业务对象,只是简单的线性事物。
我们的服务有一种获取业务对象的方法。这将返回一个基础Dto类(ILinear
),它声明BusinessObjectDto
(关系属性等)的公共部分和扩展IBusinessObject
的{{1}},并添加有关的额外信息事物的线性方面。这很好,并使客户端能够以一定程度的多态性处理返回的LinearBusinessObjectDto
。
我们还想要一种获得线性事物的方法。这将返回一个基类BusinessObjectDto
,其中包含常见的线性详细信息。简单的线性对象实现扩展BusinessObjects
,一切都很好。但是现在我遇到了一个问题,因为我不能从LinearDto
和LinearDto
扩展LinearBusinessObjectDto
,因为只支持单继承,我不能将接口用作WCF不知道什么类型然后放入WDSL中的服务合同定义。
所以我的LinearDto
开始有2个dtos,一个来自BusinessObjectDto
(LinearBusinessObject
),另一个来自LinearDto(BusinessObjectDto
)然后根据我感兴趣的界面转换每一个。
这似乎会导致许多额外的Dto类(我已经有很多),所以我想知道是否有比这更好的解决方案?或者这只是我们必须忍受的东西?
答案 0 :(得分:13)
一位智者曾告诉我,面向对象是服务的敌人。
在我看来,这是一个普遍的OO / SOA问题,而不是特定的WCF问题:我想到了“赞成组合而不是继承”的旧建议。特别是在服务方面,Polymorphic设计不应该是您在DTO层中所追求的。您应该避免使用使用继承或接口的DTO(除非您动态地序列化/反序列化,否则甚至不可能使用接口...您无法使用SVCUtil生成具体代理,因为具体类型在生成时是未知的,但是来自我的在.NET客户端中使用ChannelFactories时可以使用内存...我不记得细节了。
通常,在创建DTO / DataContracts时,只在其中定义具体的成员/属性。您的DTO模型应设计为平面和跨平台,而不是面向对象。
答案 1 :(得分:1)
我想我已经理解了你想说的话所以请原谅我,如果我错过了解释。基本上,您有以下要通过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<Type> GetKnownType()
{
yield return typeof(ClientImplementationOfA);
yield return typeof(ClientImplementationOfB);
yield return typeof(ClientImplementationOfAAndB);
}
是的,这确实引入了另一个DTO对象,但它只需要存在于客户端上,这意味着您的整个合同都是通过接口实现的,您可以更改客户端或服务器上不同对象的实现/交换而不会产生任何影响只要合同没有被打破,另一方面。如果在正确的范围内正确完成,您甚至可以在不破坏现有客户端的情况下引入新的属性和方法。
答案 2 :(得分:0)
WCF提供了一个钩子,用于在接口和继承链上定义“已知类型”。我不确定使用ServiceKnownType attribute或KnownType attribute是否直接适用于您所描述的内容,但绝对值得一看。
答案 3 :(得分:0)
这是内部网络服务还是外部托管?
如果这是内置的,请查看“配置服务参考”对话
中的“引用程序集中的重用类型”选项在客户项目中引用您的DTO程序集(确保您的DTO在他们自己的程序集中)
打开目标WCF服务的“配置服务参考”对话框
选中“在引用的程序集中重用类型”复选框
选择“在指定的引用程序集中重用类型”单选按钮
从列表中选择DTO程序集。
您从ServiceClient()
收到的结果将是引用的DTO程序集中的实际类型,而不是生成的代理。你现在应该能够多态地对你的对象采取行动。
答案 4 :(得分:0)
也许您可以封装基础对象。因此,您拥有BusinessObjectDto和LinearDto对象。然后,让您的LinearBusinessObjectDto包含两个属性,一个是BusinessObjectDto类型,另一个是LinearObjectDto类型。当service方法返回一个LinearBusinessObjectD时,它会初始化每个属性。然后,您可以在LinearBusinessObjectDto上实现接口,并删除对每个属性的调用。不幸的是,在客户端上你可以转换为所需的界面,但你应该能够选择你想要使用的属性。
编辑:不确定DTO部分的接口...不知道是否会在带有接口的客户端上创建实现接口的DataContract属性类??!
答案 5 :(得分:0)
请阅读以下帖子
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);
}
答案 6 :(得分:0)
为什么不使用合成而不是继承?如果失败了,PostSharp会有多重继承吗?