0

我非常坚持将 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,我创建了 ServiceContract 和 DataContracts 的 WCF 代理(顺便说一句:没有引用我可以放置上述定义的 DataContracts 的通用“App.Contracts.dll”),用于从客户端传输数据到服务器,我现在一切就绪......

但是从客户端的用户功能方面来看,还有很长的路要走。

我想确保用户可以使用上述属性,但在实例化客户端对象时会进行一些类型检查。例如,我希望用户使用的实际类看起来更像:

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;}}
}

非常感谢任何和所有的建议!

4

3 回答 3

2

我认为非常重要的是要注意消息/数据合同在面向服务的环境中具有非常特定的目的。消息是需要在客户端和服务器之间传输的信息包(反之亦然)。如果您的客户端需要特定的行为,那么您应该有特定于客户端的类型来满足客户端的特定需求。这些类型应该由某种适配器或外观来填充,这些适配器或外观包装了您的服务引用,尽可能从服务中抽象出您的客户端应用程序,并提供必要的行为、规则和适当的限制。

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.
于 2009-07-22T01:40:36.390 回答
1

你正在寻找不该存在的东西。客户端上的类型通常不会与服务器上的类型相同,而且通常也不应该如此。在一般情况下,客户端甚至不会运行 .NET。

请记住,这些数据契约旨在成为某些 XML 消息的 XML Schema 定义,这些消息将从客户端流向服务。XML Schema 不描述诸如只读之类的编程语言概念。

如果您觉得您需要客户端拥有这样的 API,那么您确实需要他们使用您必须提供的程序集。此程序集可能包含与服务器正在使用的完全相同的数据协定类型,但可能包含一组仅供客户端使用的类型。当然,您必须保持两组类型兼容(每个数据成员的名称、顺序、类型和名称空间相同)。

于 2009-07-22T01:37:49.997 回答
0

失去了我的编辑点/匿名个人资料……但只想对你们俩的明确答案表示感谢。让我继续以下解决方案:

  • ClientMessage 在服务器上,在客户端上创建一个代理,没有直接依赖。
  • 在具有镜像 poco/wcf ClientMessage 名称的属性的客户端上创建消息,但添加了 arg 检查等。
  • 为 VisualStudio 生成的 ClientMessage 创建了 Extension 方法,使用静态 Extension 方法 MapFrom(this ClientMessage thisClientMessage, Message message){...} 从面向客户端的消息映射到传输消息对象。
  • 关闭它。

服务器上的 ClientMessage 可以具有逻辑,以便网页将其用作支持对象。即使在同一台服务器上,来回映射它们的成本也会更高,但我可以从两种场景(网络和远程客户端)中剪切/粘贴/使用相同的客户端逻辑中获益。(除非有人也看到这个逻辑的错误:-) ...)

再次谢谢你。

于 2009-07-22T21:44:08.813 回答