如何根据WCF中的内容自定义数据序列化?

时间:2012-03-20 16:38:24

标签: wcf serialization

尝试序列化类似联合的数据类型。有一个枚举字段,指示联合中存储的数据类型,以及各种可能的字段类型。

所需的结果是DataContractSerializer生成的XML,其中只包含枚举和相关字段。

可能的解决方案,还没有尝试过,是:

  • 使用自定义序列化程序并使用自定义属性标记联合属性,类似于this question。自定义序列化程序将删除不需要的成员。
  • 使用ISerializationSurrogate并序列化仅包含相关数据的其他对象。
  • 不要在联合中使用单独的字段,使用一个对象字段(这可以用作ISerializationSurrogate方法实现的一部分)。
  • 其他......?

例如:

[DataContract]
public class WCFTestUnion
{
    public enum EUnionType
    {
        [EnumMember]
        Bool,
        [EnumMember]
        String,
        [EnumMember]
        Dictionary,
        [EnumMember]
        Invalid
    };

    EUnionType unionType = EUnionType.Invalid;

    bool boolValue = true;
    string stringValue = "Hello";
    IDictionary<object, object> dictionaryValue = null;

    // Could use custom attribute here ?
    [DataMember]
    public bool BoolValue
    {
        get { return this.boolValue; }
        set { this.boolValue = value; }
    }

    // Could use custom attribute here ?
    [DataMember]
    public string StringValue
    {
        get { return this.stringValue; }
        set { this.stringValue = value; }
    }

    // Could use custom attribute here ?
    [DataMember]
    public IDictionary<object, object> DictionaryValue
    {
        get { return this.dictionaryValue; }
        set { this.dictionaryValue = value; }
    }

    [DataMember]
    public EUnionType UnionType
    {
        get { return this.unionType; }
        set { this.unionType = value; }
    }
} // Ends class WCFTestUnion

测试

    class TestSerializeUnion
    {
        internal static void Test()
        {
            Console.WriteLine("===TestSerializeUnion.Test()===");

            WCFTestUnion u = new WCFTestUnion();
            u.UnionType = WCFTestUnion.EUnionType.Dictionary;
            u.DictionaryValue = new Dictionary<object, object>();
            u.DictionaryValue[1] = "one";
            u.DictionaryValue["two"] = 2;

            System.Runtime.Serialization.DataContractSerializer serialize = new System.Runtime.Serialization.DataContractSerializer(typeof(WCFTestUnion));
            System.IO.Stream stream = new System.IO.MemoryStream();

            serialize.WriteObject(stream, u);

            stream.Seek(0, System.IO.SeekOrigin.Begin);
            byte[] buffer = new byte[stream.Length];
            int length = checked((int)stream.Length);
            int read = stream.Read(buffer, 0, length);
            while (read < stream.Length)
            {
                read += stream.Read(buffer, 0, length - read);
            }

            string xml = Encoding.Default.GetString(buffer);

            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            doc.LoadXml(xml);

            System.Xml.XmlTextWriter xmlwriter = new System.Xml.XmlTextWriter(Console.Out);
            xmlwriter.Formatting = System.Xml.Formatting.Indented;

            doc.WriteContentTo(xmlwriter);
            xmlwriter.Flush();

            Console.WriteLine();
        }
    } // Ends class TestSerializeUnion

输出:

<WCFTestUnion xmlns="http://schemas.datacontract.org/2004/07/WCFTestServiceContracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <BoolValue>true</BoolValue>
  <DictionaryValue xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <a:KeyValueOfanyTypeanyType>
      <a:Key i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">1</a:Key>
      <a:Value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">one</a:Value>
    </a:KeyValueOfanyTypeanyType>
    <a:KeyValueOfanyTypeanyType>
      <a:Key i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">two</a:Key>
      <a:Value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">2</a:Value>
    </a:KeyValueOfanyTypeanyType>
  </DictionaryValue>
  <StringValue>Hello </StringValue>
  <UnionType>Dictionary</UnionType>
</WCFTestUnion>

所需输出(仅使用的字段序列化,连同枚举):

<WCFTestUnion xmlns="http://schemas.datacontract.org/2004/07/WCFTestServiceContracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <DictionaryValue xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <a:KeyValueOfanyTypeanyType>
      <a:Key i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">1</a:Key>
      <a:Value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">one</a:Value>
    </a:KeyValueOfanyTypeanyType>
    <a:KeyValueOfanyTypeanyType>
      <a:Key i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">two</a:Key>
      <a:Value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">2</a:Value>
    </a:KeyValueOfanyTypeanyType>
  </DictionaryValue>
  <UnionType>Dictionary</UnionType>
</WCFTestUnion>

1 个答案:

答案 0 :(得分:2)

这里有几个选项。您使用的内容取决于此场景的复杂程度(除此之外您还必须执行此类操作,您需要多长时间以及以何种方式序列化此数据,性能等)。看看这些选项,请问您是否有更多的问题,但大多数情况下,我建议你在选择一个或一个混合解决方案之前,先从下面的列表中玩和尝试多种策略。

  • Use a data contract resolver。提供一种机制,用于在序列化和反序列化期间动态映射类型与线表示之间的类型,使您可以灵活地支持比开箱即用更多的类型。

  • Use IObjectReference。您可以拥有一个类,该类在反序列化后实现并返回对其他对象的引用。

  • Use a data contract surrogate。这与您所指的序列化代理不同,但也有类似之处。我认为这些可能很适合你