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

Я застрял в одной части использования 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 для a 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 ]

2 голосов
/ 22 июля 2009

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

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.
1 голос
/ 22 июля 2009

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

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

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

0 голосов
/ 23 июля 2009

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

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

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

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

...