服务 – 客户端界面,架构建议

我有一个Windows WCF服务和Web客户端。 我的服务有一种方法

[OperationContract] SubmitOrder(OrderInfo info).... // class used to pass all relevant data [DataContract] class OrderInfo { [DataMember] OrderType Type; // general order data } 

在我引入新的订单类型(由OrderInfo.Type属性控制)之前,这很棒。 您可以将新订单类型视为从一般订单(行为方面)派生而来。 每个新订单都有一些额外的属性。 实现Order的这种多态行为的最佳方法是什么?

目前,我只是在添加新订单时向OrderInfo类添加新属性。

 [DataContract] class OrderInfo { [DataMember] OrderType Type; // general order data // First custom order data // Second custom order data // TODO - add new properties for new orders } 

我不喜欢它太多因为它太直。 如果我更改[DataContract]并且未重建客户端怎么办?

我有什么选择? 我当然可以实现inheritance并派生新的[DataContract]类,如MyCustomOrder1 ,但序列化不支持inheritance,我需要使用由于某些原因而被禁止的[KnownTypes]

在我的头脑中,我不确定这是一个好主意,但我认为这样做的方法是放松你在服务方面的合同,例如使用MessageContract而接受“任何”内容。信息。 您仍然可以将您的数据交换分发给您的客户,这样您就可以根据模型对客户进行编程。 在服务方面,您需要确定消息包含的内容类型并采取相应措施。

我不确定如何实现这一点的细节,但我首先看一下WCF中的Message类: http : //msdn.microsoft.com/en-us/library/ms734675.aspx

它归结为使用’untyped’消息,如下所述: http : //geekswithblogs.net/claeyskurt/archive/2008/09/24/125430.aspx如前所述: WCF和匿名类型


一个完全不同的方式(也许更干净?)这样做是使用IExtensibleDataObject,如本文第2部分所述: http://geekswithblogs.net/claeyskurt/archive/2008/05/02/121848.aspx 。


编辑:我正在阅读有关数据合同版本控制的内容 ,我想到了什么是更好的解决方案

如果由于某种原因您无法使用KnownType,那么您所做的就是创建新版本的合同。 最简单的方法是

  • 使用子类型的所有属性创建单个orderinfo合约
  • 添加一个’type’属性(一个字符串,因为你之后不能再添加新的枚举,这将是一个突破性的变化)
  • 使基类上的所有属性“必需”
  • 使子类型上的所有属性“可选”
  • 实现IExtensibleDataObject是向前兼容的
  • 在我们的服务中,使用type属性来确定它的顺序和行为

现在,当您添加新类型时,将新属性添加到OrderInfo类,只要它们是可选的并且类的其余部分不会更改,您将向后兼容您的客户端有合同的新版本。 是的,它可能会在客户端变得混乱,但你总是可以在一些助手类后面抽象出来。

我需要使用由于某些原因而被禁止的[KnownType]。

禁止是什么意思? 我使用KnownTypeAttribute没有任何问题。 这是一个例子。

 [DataContract] [KnownType( typeof( NetworkDeviceProperties ) )] public class DeviceProperties { [DataMember] public string MachineName { get; set; } } [DataContract] public class NetworkDeviceProperties : DeviceProperties { [DataMember] public IPAddress IPAddress { get; set; } } [ServiceContract] public interface ICollectionService { [OperationContract] [ServiceKnownType( typeof( NetworkDeviceProperties ) )] void Start( DeviceProperties properties ); } 

在我的客户端,我创建一个NetworkDeviceProperties对象,并将其无问题地传递给Start()方法。 有关其他信息,请参阅此博客 。