嵌套复合对象的WCF XMLserialization

嵌套复合对象的WCF XMLserialization,xml,wcf,serialization,object,composite,Xml,Wcf,Serialization,Object,Composite,嗨,我有一个服务契约,在它的实现中,我试图将它接收到的请求参数写入一个文本文件。这里,“TypeA”的复合对象作为参数传递 namespace WebService { // NOTE: If you change the interface name "IRequestStatusChanged" here, you must also update the reference to "IRequestStatusChanged" in App.config.

嗨,我有一个服务契约,在它的实现中,我试图将它接收到的请求参数写入一个文本文件。这里,“TypeA”的复合对象作为参数传递

        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格式接收的所有参数写入一个文件,以便它们可读(类似于日志文件)。

类型“TypeB”和“TypeC”不会写入文件,因为它们不是必需的-当序列化程序序列化或反序列化TypeA实例时,它知道成员“b”的类型是
TypeB
,因此它不会写入类型信息。你也需要这些信息吗?由于您正在序列化a
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()));
    }
}
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()));
    }
}
另一个选项(我真的不建议这样做,因为为了日志记录,您需要更改系统的逻辑)是将字段声明为
object
。这样,由于声明的类型不同于实际的类型,因此类型信息将被写出-请参见下文

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

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

但是,您在这里使用了两种不同的序列化框架-
DataContractSerializer
被WCF隐式使用,除非您另有说明,以及
XmlSerializer
。为什么不直接使用
DataContractSerializer
,因为您已经获得了WCF所需的所有属性

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

当您的客户端发送TypeA对象时,它是否为TypeB的TypeC设置了一个值?如果它们都为空,序列化程序可能不会将它们提交到文件中。非常感谢您提供的信息。非常有用。请求是以XML格式接收的,因此我希望将其写入XML或纯文本格式的文件中,以便可读。是的,我还需要写TypeB和TypeC对象。如果我能找到某种方法将整个复合对象写入一个文件,那就太好了。请求是否包含您想要的类型信息?如果是这样,您可以考虑使用MessageInspector(IDISPATCHMESSAGECHECUTROR)来记录该请求。在OP的问题中,我没有看到任何需要类型信息的问题,只是嵌套的值没有被写入。这是因为
XmlSerializer
不会涉及非公共成员。我已经将成员声明为公共成员,很抱歉我错过了这里。根据以上信息,我猜XMLseralizer不会序列化嵌套对象。它将只序列化单个指定类型的对象。@user832219,如果您将其声明为public,我建议您更新文章中的代码。你能说明你需要什么吗?您需要序列化TypeB/TypeC的实例(如果它们是公共的,XmlSerializer应该这样做),还是除了它们的实例之外还需要序列化它们的类型名?