Как я могу создать более умные (то есть типизированные проверенные / доступные только для чтения) объекты Client DataContract?

Я застрял в одной части использования WCF для системы обмена сообщениями клиент / сервер, и был бы очень признателен за помощь.

На сервере у меня есть объект Message DataContract, в котором одно из свойств указывает на типизированную коллекцию MessageBody DataContracts. Урезанная версия класса выглядит следующим образом:

[DataContract]
class Message {

  [DataMember]
  string From;

  [DataMember]
  string To;

  [DataMember]
  string Subject{get;set;}

  [DataMember]
  MessageBodies {get;}
}

[DataContract]
class MessageBodies : CollectionBase<MessageBody>{}

[DataContract]
class MessageBody {
  [DataMember]
  BodyType Type get {get;set;}

  [DataMember]
  string Body {get;set;}
}

Из файла App.Client.dll я создаю прокси WCF для объектов ServiceContract и DataContracts (кстати: нет ссылки на общий файл App.Contracts.dll, в который я мог бы поместить определенные выше DataContracts), для передачи данных из клиента к серверу я сейчас все настроил...

Но со стороны функциональности пользователя на стороне клиента, есть еще пути.

Я хочу убедиться, что пользователи могут работать с вышеупомянутыми свойствами, но с некоторой проверкой типов происходит, когда они создают экземпляры клиентских объектов. Например, я хотел бы, чтобы фактический класс, с которым работают пользователи, выглядел больше как:

class MessageBody {
  //ReadOnly only:    
  public BodyType Type get {get {return _Type;}}
  private BodyType _Type;

  //Validated property:
  public string Body {
    get{ return _Body;}
    set{
      if (value == null){throw new ArgumentNullException();}
      _Body = value;
      }
  }
  private string _Body;

  //Set via Constructor only:
  public MessageBody (BodyType type, string body){
    //validate type and body first...
    _Type = type;
    _Body = body;
  }
}

Одно из направлений, которое я пытался использовать для решения этой проблемы, было следующим:

Если бы я переименовал DataContract из Message в CommMessage, я мог бы затем обернуть объект POCO/WCF более умным объектом... Но хотя это будет работать для большинства свойств, за исключением свойств коллекции:

public Message {
  CommMessage _InnerMessage;

  public string Subject {get {_InnerMessage.Subject;}}

  //Option 1: give direct access to inner object...but they are just poco's...
  public CommMessageBodies MessageBodies { get {_InnerMessage.Addresses;}} 

  //Option 2...don't have one yet...what I would like is something like
  //this (returning MessageBody rather than CommMessageBody):
  //public MessageBodies MessageBodies {get {_InnerMessage.Bodies;}}
}

Большое спасибо за любые предложения!

3 ответа

Я думаю, что очень важно отметить, что сообщения / контракты имеют очень специфическое назначение в сервис-ориентированной среде. Сообщение - это пакет информации, который должен быть передан между клиентом и сервером (или наоборот). Если вашему клиенту требуется определенное поведение, то у вас должны быть типы, специфичные для клиента, которые соответствуют конкретным потребностям клиента. Эти типы должны быть заполнены каким-то адаптером или фасадом, который оборачивает ваши ссылки на сервисы, максимально абстрагируя ваше клиентское приложение от сервиса и предоставляя необходимое поведение, правила и ограничения в зависимости от ситуации.

using WCF.ServiceClientReference; // Contains WCF service reference and related data contracts

class ServiceFacade
{
    private ServiceClient m_client;

    void SendMessage(ClientMessage message)
    {
        Message serviceMessage = new Message
        {
            Subject = message.Subject,
            MessageBodies = new CommMessageBodies(message.MessageBodies.Select(b => new CommMessageBody(b))
        }

        m_client.SendMessage(serviceMessage);
    }
}

class ClientMessage
{
    public ClientMessage()
    {
        MessageBodies = new List<ClientMessageBody>();
    }

    public string Subject {get; }
    public IList<ClientMessageBody> MessageBodies { get; private set; } 
}

// etc.

Вы ищете что-то, чего не должно быть там. Типы на клиенте, как правило, не будут такими же, как типы на сервере, и, как правило, они не должны быть. В общем случае клиент даже не будет запускать.NET.

Помните, что эти Контракты с данными должны стать определениями XML-схемы некоторых сообщений XML, которые будут передаваться от клиента к сервису. Схема XML не описывает понятия языка программирования, такие как "Только чтение".

Если вы чувствуете, что вам нужно, чтобы клиенты имели такой API, тогда вам нужно, чтобы они использовали сборку, которую вам нужно будет предоставить. Эта сборка может содержать те же типы контрактов данных, которые использует сервер, но потенциально может содержать набор типов, предназначенных исключительно для использования клиентами. Конечно, вам нужно будет поддерживать совместимость двух наборов типов (одинаковое имя, порядок, тип и пространство имен для каждого элемента данных).

Потерял мои точки редактирования / анон профиль... но просто хотел сказать спасибо вам обоим за четкие ответы. Я перешел к следующему решению:

  • ClientMessage на сервере, создавая прокси для этого на клиенте, без прямой зависимости.
  • создать сообщение на клиенте, которое имеет свойства, которые отражают имена poco/wcf ClientMessage, но с добавленной проверкой аргументов и т. д.
  • создал метод Extension для VisualStudio, сгенерированный ClientMessage, со статическим методом Extension MapFrom(this ClientMessage thisClientMessage, Message message){...} для сопоставления сообщения, обращенного к клиенту, для транспортировки объекта сообщения.
  • прочь идет

ClientMessage на сервере может иметь логику, чтобы веб-страницы использовали его в качестве объекта поддержки. Стоит немного больше, чтобы отобразить их туда и обратно, даже если они находятся на одном и том же сервере, но я выигрываю от возможности вырезать / вставлять / использовать одну и ту же логику клиента для обоих сценариев (веб-клиент и удаленный клиент). (Если никто не видит ошибку с этой логикой также:-) ...)

Еще раз спасибо.

Другие вопросы по тегам