我的目标是否可以使用WCF(这是正确的做事方式吗?)

时间:2010-04-05 23:14:52

标签: c# wcf serialization

我正在编写一些修改Windows Server配置的软件(如MS-DNS,IIS,文件系统的一部分)。我的设计有一个服务器进程,用于构建服务器配置状态的内存中对象图和请求此对象图的客户端。然后,服务器将序列化图形,将其发送到客户端(可能使用WCF),然后服务器对此图形进行更改并将其发送回服务器。服务器接收图表并继续对服务器进行修改。

但是我了解到WCF中的对象图序列化并不像我原先想象的那么简单。我的对象具有层次结构,并且许多具有参数化构造函数和不可变属性/字段。还有许多集合,数组和字典。

我对WCF序列化的理解是它需要使用XmlSerializer或DataContractSerializer,但是DCS对我的对象图的设计施加了限制(不可变数据似乎是正确的,它还需要无参数构造函数)。我理解XmlSerializer允许我使用自己的类,只要它们实现ISerializable并具有反序列化构造函数。我很好。

我和我的一个朋友谈过这个问题,他主张采用仅限数据传输对象的路线,在那里我必须维护一个单独的DataContract对象图来传输数据并重新实现我的服务器客户端上的对象。

我的另一位朋友说,因为我的服务只有两个操作(“GetServerConfiguration”和“PutServerConfiguration”),所以完全跳过WCF并实现我自己的使用套接字的服务器可能是值得的。

所以我的问题是:

  • 以前是否有人遇到类似的问题,如果有,有更好的方法吗?将整个对象图发送到客户端进行处理是否明智?我是否应该将其分解,以便客户端在需要时请求对象图的一部分并仅发送已更改的位(从而减少与并发相关的风险?)?
  • 如果向下发送对象图是正确的方法,WCF是正确的工具吗?
  • 如果WCF是对的,那么让WCF序列化我的对象图的最佳方法是什么?

2 个答案:

答案 0 :(得分:3)

对象图可以与DataContract序列化一起使用。

注意:确保您保留对象引用,这样当它们都应该是相同的引用时,您最终不会得到图中同一对象的多个副本,默认情况下行为不会保留这样的身份。

这可以通过在构建DataContractSerializer时指定preserveObjectReferences参数或为true上的IsReference属性指定DataContractAttribute来完成(最后一个属性)需要.NET 3.5SP1 )。

但是,当通过WCF发送对象图时,如果不注意确保图形保持合理的大小,则存在与WCF配额相冲突的风险(并且有很多)。

对于net.tcp传输,例如,要设置的重要内容包括maxReceivedMessageSizemaxStringContentLengthmaxArrayLength。更不用说图形(maxObjectsInGraph)中允许的65335个不同对象的隐藏配额,只能被忽略。

您还可以使用仅使用DataContractSerializer公开读取访问器的类,并且没有无参数构造函数:

using System;
using System.IO;
using System.Runtime.Serialization;

class DataContractTest
{
    static void Main(string[] args)
    {
      var serializer = new DataContractSerializer(typeof(NoParameterLessConstructor));

      var obj1 = new NoParameterLessConstructor("Name", 1);

      var ms = new MemoryStream();
      serializer.WriteObject(ms, obj1);

      ms.Seek(0, SeekOrigin.Begin);

      var obj2 = (NoParameterLessConstructor)serializer.ReadObject(ms);

      Console.WriteLine("obj2.Name: {0}", obj2.Name);
      Console.WriteLine("obj2.Version: {0}", obj2.Version);
    }

    [DataContract]
    class NoParameterLessConstructor
    {
        public NoParameterLessConstructor(string name, int version)
        {
          Name = name;
          Version = version;
        }

        [DataMember]
        public string Name { get; private set; }
        [DataMember]
        public int Version { get; private set; }
    }
}

这是有效的,因为DataContractSerializer可以在不调用构造函数的情况下实例化类型。

答案 1 :(得分:0)

你让自己与序列化器混淆了:

  • XmlSerializer 需要一个无参数构造函数,因为在反序列化时,.NET运行库将实例化该类型的新对象,然后设置其属性

  • DataContractSerializer 没有此类要求

查看blog post by Dan Rigsby解释序列化器的所有荣耀并比较两者。

现在为您的设计 - 我的主要问题是:是否有一个函数可以返回所有设置,客户端操作那些,然后另一个函数接收所有信息?

难道你不能将这些东西分解成更小的块,更小的方法调用吗?例如。有单独的服务方法来设置配置的每个单独项目?那样,你可以

  • 减少通过网络发送的数据量 - 要序列化和反序列化的对象图将更加简单
  • 使您的配置服务更精细 - 例如如果有人需要设置一个小的属性,那个客户端不需要读取整个大服务器配置,设置一个单独的属性,并发送回巨大的大块 - 只需调用适当的方法来设置一个属性