Сервис - клиентский интерфейс, совет по архитектуре - PullRequest
2 голосов
/ 15 декабря 2009

У меня есть служба Windows WCF и веб-клиент. Мой сервис имеет один метод

[OperationContract]
SubmitOrder(OrderInfo info)....

// class used to pass all relevant data
[DataContract]
class OrderInfo
{
 [DataMember]
 OrderType Type;
 // general order data
}

Это было здорово, пока я не ввел новые типы заказов (управляется свойством OrderInfo.Type). Вы можете думать о новом типе заказа как производном от общего порядка (с точки зрения поведения). Каждый новый заказ имеет некоторые дополнительные свойства. Каков наилучший подход к реализовать это полиморфное поведение порядка?

В настоящее время я просто добавляю новые свойства в класс 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] и клиента не перестроен?

Какие у меня альтернативы? Конечно, я могу реализовать наследование и получить новый класс [DataContract], такой как MyCustomOrder1, но наследование не поддерживается сериализацией, мне нужно использовать [KnownTypes], что запрещено по некоторым причинам.

Ответы [ 2 ]

5 голосов
/ 15 декабря 2009

Сверху головы, и я не уверен, что это отличная идея, но я думаю, что способ сделать это состоял бы в том, чтобы ослабить ваши контракты на стороне обслуживания, например. вместо этого используйте MessageContract и принимайте «любой» контент в сообщении. Вы по-прежнему можете распространять свои контракты на передачу данных своим клиентам, поэтому у вас есть преимущество в программировании вашего клиента на основе модели. Что касается службы, вам необходимо выяснить, какой контент содержится в сообщении, и действовать соответственно.

Я не уверен в деталях, как реализовать это, но я бы начал с просмотра класса Message в WCF: http://msdn.microsoft.com/en-us/library/ms734675.aspx

Это сводится к использованию «нетипизированных» сообщений, как описано здесь: http://geekswithblogs.net/claeyskurt/archive/2008/09/24/125430.aspx, как обсуждалось здесь ранее: WCF и анонимные типы


Совершенно другим способом (и, может быть, чище?) Для этого будет использование IExtensibleDataObject, как описано во второй части этого поста http://geekswithblogs.net/claeyskurt/archive/2008/05/02/121848.aspx.


edit: я читал о версии контракта данных и думал о том, что может быть лучшим решением

Если по какой-либо причине вы не можете использовать KnownType, то, что вы делаете, сводится к созданию новых версий вашего контракта. Самый простой способ начать было бы с

  • создать единый контракт с информацией о заказах со всеми свойствами подтипов
  • добавить свойство 'type' (строка, потому что вы не можете просто добавить новые перечисления после этого, это будет серьезное изменение)
  • сделать все свойства, которые были в базовом классе 'обязательными'
  • сделать все свойства, которые были для подтипов 'необязательными'
  • реализовать IExtensibleDataObject для прямой совместимости
  • в нашем сервисе, используйте свойство type, чтобы определить тип заказа и действуйте соответственно

Теперь, когда вы добавляете новые типы, добавляете новые свойства в класс OrderInfo, и пока они не являются обязательными, а остальная часть класса не изменяется, вы будете обратно совместимы с вашими клиентами, которые У вас еще нет новой версии вашего контракта. Да, на стороне клиента это может запутаться, но вы всегда можете абстрагироваться от некоторых вспомогательных классов.

3 голосов
/ 15 декабря 2009

Мне нужно использовать [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 (). Обратитесь к этому блогу за дополнительной информацией.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...