嵌套复合对象的WCF XML序列化

时间:2011-07-12 15:23:37

标签: xml wcf serialization object composite

您好我有服务合同,并且在其实现中我试图在文本文件中编写它接收的请求参数。这里将'TypeA a'的复合对象作为参数传递。

        namespace WebService
{
    // NOTE: If you change the interface name "IRequestStatusChanged" here, you must also update the reference to "IRequestStatusChanged" in App.config.
    [ServiceContract]
    public interface IRequestStatusChanged
    {
        [OperationContract]
        Input StatusChanged(Input In);

    }

    [Serializable] [DataContract]
    public class Input
    {
        [DataMember]
        RequestStatus RS = new RequestStatus();

    }

    [Serializable] [DataContract]
    public class RequestStatus
    {
        [DataMember]
        RequestToken RT = new RequestToken();

        [DataMember]
        public String State

    }
    [Serializable] [DataContract]
    public class RequestToken
    {
        [DataMember]
        public string Id;
    }
}

Implementation of contract

namespace WebService
{
    // NOTE: If you change the class name "RequestStatusChanged" here, you must also update the reference to "RequestStatusChanged" in App.config.
    public class RequestStatusChanged : IRequestStatusChanged
    {
        public Input StatusChanged(Input In)
        {


           /* IFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            Stream outfile = new FileStream(@"C:\test.txt", FileMode.Open,FileAccess.Write);
            formatter.Serialize(outfile, In);
            outfile.Close(); */


            XmlSerializer serializer = new XmlSerializer(typeof(Input));
            TextWriter TW = new StreamWriter(@"c:\test.xml");
            serializer.Serialize(TW, In);
            TW.Close();

            return In;
        }

    }
}

之前我尝试使用IFORMATTER序列化对象并将其写入文本文件,但它不是人类可读的,所以我尝试了xml序列化。

当我检查写入的XML文件时,它只有“TypeA”对象的标签,并且不会将“TypeB”和“TypeC”对象写入文件。我已将所有类标记为服务合同中的[Serializable]。我想将以文本或xml格式接收的所有参数写入文件,以便它们可读(日志文件的种类)。

2 个答案:

答案 0 :(得分:2)

类型'TypeB'和'TypeC'没有写入文件,因为它们不是必需的 - 当序列化程序序列化或反序列化TypeA的实例时,它知道成员'b'的类型是TypeB,因此它不会写入类型信息。你还需要这些信息吗?由于您要序列化TypeA,并且您知道字段b的类型为TypeB,因此您不需要日志文件中的额外信息。

在WCF使用的所有序列化程序中,唯一可以“强制”写入类型的是JSON序列化程序 - 但是你会得到结果为JSON,而不是XML - 见下文。

public class StackOverflow_6666697
{
    [DataContract]
    public class TypeA { [DataMember] public TypeB b = new TypeB(); }
    [DataContract]
    public class TypeB { [DataMember] public TypeC c = new TypeC(); }
    [DataContract]
    public class TypeC { [DataMember] public string S1; }
    public static void Test()
    {
        MemoryStream ms = new MemoryStream();
        XmlWriterSettings ws = new XmlWriterSettings
        {
            Indent = true,
            IndentChars = "  ",
            OmitXmlDeclaration = true,
            Encoding = Encoding.UTF8
        };
        TypeA instance = new TypeA { b = new TypeB { c = new TypeC { S1 = "Hello world" } } };

        XmlWriter w = XmlWriter.Create(ms, ws);
        new XmlSerializer(typeof(TypeA)).Serialize(w, instance);
        w.Flush();
        Console.WriteLine("XmlSerializer:");
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));

        ms.SetLength(0);
        w = XmlWriter.Create(ms, ws);
        new DataContractSerializer(typeof(TypeA)).WriteObject(w, instance);
        w.Flush();
        Console.WriteLine("DataContractSerializer:");
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));

        ms.SetLength(0);
        w = XmlWriter.Create(ms, ws);
        new NetDataContractSerializer().WriteObject(w, instance);
        w.Flush();
        Console.WriteLine("NetDataContractSerializer:");
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));

        ms.SetLength(0);
        w = JsonReaderWriterFactory.CreateJsonWriter(ms, Encoding.UTF8);
        new DataContractJsonSerializer(typeof(TypeA), null, 65536, false, null, true).WriteObject(w, instance);
        w.Flush();
        Console.WriteLine("DataContractJsonSerializer:");
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
    }
}

另一个选项(我真的不建议,因为你为了记录而改变系统的逻辑)是将字段声明为object。这样,由于声明的类型与实际类型不同,因此将写出类型信息 - 见下文。

public class StackOverflow_6666697
{
    [DataContract]
    public class TypeA { [DataMember] public object b = new TypeB(); }
    [DataContract]
    public class TypeB { [DataMember] public object c = new TypeC(); }
    [DataContract]
    public class TypeC { [DataMember] public string S1; }
    public static void Test()
    {
        MemoryStream ms = new MemoryStream();
        XmlWriterSettings ws = new XmlWriterSettings
        {
            Indent = true,
            IndentChars = "  ",
            OmitXmlDeclaration = true,
            Encoding = Encoding.UTF8
        };
        TypeA instance = new TypeA { b = new TypeB { c = new TypeC { S1 = "Hello world" } } };

        XmlWriter w = XmlWriter.Create(ms, ws);
        new XmlSerializer(typeof(TypeA), new Type[] { typeof(TypeB), typeof(TypeC) }).Serialize(w, instance);
        w.Flush();
        Console.WriteLine("XmlSerializer:");
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));

        ms.SetLength(0);
        w = XmlWriter.Create(ms, ws);
        new DataContractSerializer(typeof(TypeA), new Type[] { typeof(TypeB), typeof(TypeC) }).WriteObject(w, instance);
        w.Flush();
        Console.WriteLine("DataContractSerializer:");
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));

        ms.SetLength(0);
        w = XmlWriter.Create(ms, ws);
        new NetDataContractSerializer().WriteObject(w, instance);
        w.Flush();
        Console.WriteLine("NetDataContractSerializer:");
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));

        ms.SetLength(0);
        w = JsonReaderWriterFactory.CreateJsonWriter(ms, Encoding.UTF8);
        new DataContractJsonSerializer(typeof(TypeA), new Type[] { typeof(TypeB), typeof(TypeC) }, 65536, false, null, true).WriteObject(w, instance);
        w.Flush();
        Console.WriteLine("DataContractJsonSerializer:");
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
    }
}

答案 1 :(得分:0)

XmlSerializer仅序列化公共成员。您定义的DataContract类型中的所有成员都没有任何访问说明符,因此它们默认为私有。

但是,您在这里使用了两个不同的序列化框架 - 除非您另有说明,否则WCF会隐式使用DataContractSerializerXmlSerializer。为什么不使用DataContractSerializer,因为您已经拥有了WCF所需的所有属性?

var serialiser = new DataContractSerializer(typeof(TypeA));
serialiser.WriteObject(xmlWriter, typeAObj);