Как я могу создать «более умные» (т. Е. Типизированные проверенные / только для чтения) объекты 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;}}
}

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


person Community    schedule 21.07.2009    source источник


Ответы (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.
person jrista    schedule 22.07.2009

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

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

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

person John Saunders    schedule 22.07.2009

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

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

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

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

person Community    schedule 22.07.2009