2 votes

WCF XMLserialization of nested composite objects (en anglais)

Bonjour J'ai un contrat de service et dans son implémentation j'essaie d'écrire les paramètres de la requête qu'il reçoit dans un fichier texte. Ici, un objet composite de 'TypeA a' est passé en paramètre.

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

    }
}

Auparavant, j'ai essayé IFORMATTER pour sérialiser l'objet et l'écrire dans un fichier texte, mais il n'est pas lisible par l'homme, alors j'ai essayé la sérialisation xml.

Lorsque je vérifie le fichier XML écrit, il ne contient que des balises pour l'objet "TypeA" et n'écrit pas les objets "TypeB" et "TypeC" dans le fichier. J'ai marqué toutes les classes comme [Serializable] dans le contrat de service. Je souhaite écrire tous les paramètres reçus au format texte ou XML dans un fichier afin qu'ils soient lisibles (une sorte de fichier journal).

2voto

carlosfigueira Points 40778

Les types "TypeB" et "TypeC" ne sont pas écrits dans les fichiers parce qu'ils ne sont pas nécessaires - lorsque le sérialiseur sérialise ou désérialise une instance de TypeA, il sait que le type du membre "b" est TypeB et n'écrit donc pas l'information sur le type. Avez-vous besoin de ces informations également ? Puisque vous sérialisez un TypeA et vous savez que le champ b est du type TypeB vous n'avez pas besoin de ces informations supplémentaires dans le fichier journal.

Dans tous les sérialiseurs utilisés par WCF, le seul qui permet de "forcer" le type à être écrit en permanence est le sérialiseur JSON - mais vous obtiendrez alors le résultat sous forme de JSON, et non de XML - voir ci-dessous.

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

Une autre option (que je ne conseille pas vraiment, car vous modifieriez la logique de votre système pour des raisons de journalisation) consisterait à déclarer les champs sous la forme suivante object . De cette façon, puisque le type déclaré est différent du type réel, l'information sur le type sera écrite - voir ci-dessous.

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

0voto

shambulator Points 3765

XmlSerializer ne sérialise que public membres. Aucun des membres de l DataContract que vous avez définis n'ont pas de spécificateurs d'accès, ils sont donc privés par défaut.

Cependant, vous utilisez deux cadres de sérialisation différents - DataContractSerializer est implicitement utilisé par WCF à moins que vous ne lui disiez le contraire, et XmlSerializer . Pourquoi ne pas utiliser DataContractSerializer car vous avez déjà mis en place tous les attributs dont il a besoin pour les besoins de WCF ?

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X