none
Webserver - Serialisierung und Deserialisierung mit Arrays RRS feed

  • Frage

  • Hallo,
    ich habe eine Verbindung zu einem Webserver, dieser liefert mir Daten.
    Nun ist es so, dass ich Daten offline als Datei ablegen muss und zu gg. Zeit den letzten Zustand wieder einlesen kann.
    Speichern funktioniert teils.
    Namespace, xmlns werden bei Unterstrukturen wieder geschrieben, das will ich alles nicht.
    Einlesen in eine Struktur und es sollte als String zurückkommen.

    Wenn die Hauptstruktur ein Element mit weiteren Unterknoten hat, wird es nicht deserialisiert. Geht das dann gar nicht?
    Wer kann mir Tipps geben? Vielen Dank.

    Grüße Sandra

    XmlAttributes atts = new XmlAttributes();
    // Set to true to preserve namespaces, 
    // or false to ignore them.
    atts.Xmlns = false;
    
    
    var ns = new XmlSerializerNamespaces();
    ns.Add("", "");
    
    //XmlAttributeOverrides xover = new XmlAttributeOverrides();
    //// Add the XmlAttributes and specify the name of the element 
    //// containing namespaces.
    //xover.Add(typeof(SubmitJobHistoryRequest), "myNamespaces", atts);
    
    XmlAttributes xmlAttributes = new XmlAttributes();
    XmlAttributeOverrides xmlAttributeOverrides = new XmlAttributeOverrides();
    
    xmlAttributes.Xmlns = false;
    xmlAttributes.XmlType = new XmlTypeAttribute() { Namespace = "" };
    xmlAttributeOverrides.Add(typeof(SubmitJobHistoryRequest), xmlAttributes);
    
    //XmlWriterSettings xws = new XmlWriterSettings();
    //xws.OmitXmlDeclaration = true;
    
    using (var writer = new System.IO.StreamWriter("C:\\Temp\\Test.XML", false))
    {
    	 var serializer = new XmlSerializer(typeof(SubmitJobHistoryRequest), xmlAttributeOverrides); //xover);
    	 serializer.Serialize(writer, obj2, ns);
    	 writer.Flush();
    }
    
    //// 
     SubmitJobHistoryRequest neuNeu;
    string fileContents;
    using (FileStream fileStream = new FileStream(@"C:\\Temp\\Test.XML", FileMode.Open, FileAccess.Read, FileShare.Read))
    {
    	 neuNeu = (SubmitJobHistoryRequest)deserializer.Deserialize(fileStream);
    
    	 using (StreamReader reader = new StreamReader(fileStream))
    	 {
    		 fileContents = reader.ReadToEnd();
    		 System.Windows.Forms.MessageBox.Show(fileContents);
    	 }
    }
    

    <?xml version="1.0" encoding="utf-8"?>
    <SubmitJobHistoryRequest>
      <organization>0</organization>
      <jobId>0</jobId>
      <itemId>0</itemId>
      <jobQty>0</jobQty>
      <scrappedQty>0</scrappedQty>
      <JobProcessingData>
        <machineId xmlns="http://www.A1167.com/schemas/niwip/lm/1">06.12.2016</machineId>
        <partNumber xmlns="http://www.A1167.com/schemas/niwip/lm/1">45672</partNumber>
          <Boards xmlns="http://www.A1167.com/schemas/niwip/lm/1">
          <Board>
            <boardNumber>1</boardNumber>
            <endDate d5p1:nil="true" xmlns:d5p1="http://www.w3.org/2001/XMLSchema-instance" />
         
          </Board>
          <Board>
            <boardNumber>2</boardNumber>
            <startDate>06.12.2016</startDate>
            <endDate>06.12.2016</endDate>
            <boardAccepted d5p1:nil="true" xmlns:d5p1="http://www.w3.org/2001/XMLSchema-instance" />
            <facPerformed>FirstArticleCheck</facPerformed>
            <Actions d5p1:nil="true" xmlns:d5p1="http://www.w3.org/2001/XMLSchema-instance" />
            <Serials d5p1:nil="true" xmlns:d5p1="http://www.w3.org/2001/XMLSchema-instance" />
          </Board>
        </Boards>
      </JobProcessingData>
    </SubmitJobHistoryRequest>
    
    

    Mittwoch, 7. Dezember 2016 17:49

Antworten

  • Hallo Sandra,

    wie man ein Objekt in einen String (und nicht direkt in eine Datei) serialisieren kann, hab ich dir ja schon mehrfach gezeigt, bspw. hier:

      https://social.msdn.microsoft.com/Forums/vstudio/de-DE/d17e9b3a-ede0-41b0-b1df-90d9ea315d48/serialisierungzeilenumbruch-ident-geht-nicht?forum=visualcsharpde

    Du gehst ja einen anderen Weg, daher schau mal hier, ob diese Einstellungen dir helfen, die Namespaces loszuwerden:

      http://stackoverflow.com/questions/9332558/how-can-i-skip-xml-declaration-when-serializing

    Allerdings weiß ich nicht wirklich, was dich daran stört.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    • Als Antwort markiert Sandra Bauer Freitag, 9. Dezember 2016 16:19
    Mittwoch, 7. Dezember 2016 18:24
    Moderator
  • Hallo Sandra,

    vorab: Da deine Xml Serialisierung irgendwas komisches fabriziert, habe ich meine Standardmethoden ins Projekt integriert und die Aufrufe in den Click Events angepasst.

    public static void SerializeObject<T>(string FileName, T DataObject)
    {
        XmlSerializer Serializer = new XmlSerializer(typeof(T));
        FileStream FileStream = new FileStream(FileName, FileMode.Create);
        XmlTextWriter TextWriter = new XmlTextWriter(FileStream, Encoding.UTF8);
        TextWriter.Indentation = 4;
        TextWriter.IndentChar = ' ';
        TextWriter.Formatting = Formatting.Indented;
    
        XmlSerializerNamespaces XmlNamespace = new XmlSerializerNamespaces();
        XmlNamespace.Add(string.Empty, string.Empty);
    
        Serializer.Serialize(TextWriter, DataObject);
    
        TextWriter.Close();
        FileStream.Close();
        FileStream.Dispose();
    
    }
    
    public static T DeserializeObject<T>(string FileName)
    {
    
        T Result = default(T);
        XmlSerializer Serializer = new XmlSerializer(typeof(T));
        FileStream FileStream = new FileStream(FileName, FileMode.Open, FileAccess.Read);
        XmlTextReader TextReader = new XmlTextReader(FileStream);
        TextReader.Namespaces = true;
    
        Result = (T)Serializer.Deserialize(TextReader);
    
        TextReader.Close();
        FileStream.Close();
        FileStream.Dispose();
    
        return Result;
    
    }

    Die Aufrufe dann wie folgt:

    WebServiceClient.SerializeObject<JobProcessingDataType>( "C:\\Temp\\teSt.XML", Auftrag.GetDummyJobHistoryProcessingData() );

    und:

    JobProcessingDataType test = WebServiceClient.DeserializeObject<JobProcessingDataType>("C:\\Temp\\Test.XML");

    Die Methode "GetDummyJobHistoryProcessingData" ist ein Klon deiner Methode "SaveDummyJobHistoryProcessingData" und gibt nur das Objekt vom Typ "JobProcessingDataType" zurück .

    ---

    Um die Namespace Angaben bei der Serialisierung zu entfernen, kannst Du in der MarkingService.cs die Zeilen:

    [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.A1167.com/schemas/niwip/lm/1")]

    in

    [System.Xml.Serialization.XmlTypeAttribute()]

    ändern oder die Zeilen ganz entfernen. (Bei mir sind es vier Vorkommen)

    Die Deserialisierung klappt dann einwandfrei.

    Eine andere Option sehe ich nicht.

    Wenn Du die Zeilen:

    <Serial xsi:nil="true" />

    in

    <Serial />

    änderst, werden die Daten aber nicht so eingelesen, wie Sie geschrieben wurden. Du hast dann anstatt einem Array mit 10 Elementen und 2 Instanzen sowie 8 null Elementen dann 10 Serial Instanzen im Array, wovon die letzten 8 bei allen Eigenschaften null haben. Aber halt eben anders als das, was weggeschrieben wurde.

    Daher würde ich empfehlen, xsi:nil="true" beizubehalten.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    • Als Antwort markiert Sandra Bauer Samstag, 17. Dezember 2016 17:22
    Samstag, 17. Dezember 2016 12:24
    Moderator

Alle Antworten

  • Hallo Sandra,

    die einfachste (wenn auch nicht gerade schönste) Methode wäre, den serialisierten XML Inhalt mittels Replace zu bereinigen und dann erst zu speichern.

    :nil="true" kommt, da Du Elemente in deinen Klassen hast, die Nullable sind. der Standardnamespace "http://www.w3.org/2001/XMLSchema-instance" kommt wahrscheinlich genauso zustande. Diese Zeichenfolgen kannst Du, wie gesagt, einfach mit:

    XmlContent = XmlContent.Replace( @"d5p1:nil=""true""", String.Empty );

    entfernen. Ist nicht schön, klappt aber.

    Warum bei machineId, partNumber, ... noch ein separater Namespace steht, weiß ich nicht, da müsste man deine Klassen sehen. Aber ich nehme an, das ist so gewollt.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Mittwoch, 7. Dezember 2016 18:09
    Moderator
  • Hallo Stefan,

    ja nicht schön. Wie komme ich am schnellsten, dann auf den string?

    Am Anfang klappt es ja.

    <SubmitJobHistoryRequest>
      <organization>0</organization>
      <jobId>0</jobId>
      <itemId>0</itemId>
      <jobQty>0</jobQty>
      <scrappedQty>0</scrappedQty>
    

    Dann ist ein Member mit Array drin und da werden die xmlns="http://www geschrieben.

    OK, vielleicht weil es null ist.

    Müßte das so gehen, sprich das Speichern mit den Arrays.

    Wenn ich Dummydaten speichere, es wieder deserialize ist das Array = null.

    Vielleicht hast noch einen Tipp. Danke im Voraus.

    Grüße Sandra

    Mittwoch, 7. Dezember 2016 18:18
  • Hallo Sandra,

    wie man ein Objekt in einen String (und nicht direkt in eine Datei) serialisieren kann, hab ich dir ja schon mehrfach gezeigt, bspw. hier:

      https://social.msdn.microsoft.com/Forums/vstudio/de-DE/d17e9b3a-ede0-41b0-b1df-90d9ea315d48/serialisierungzeilenumbruch-ident-geht-nicht?forum=visualcsharpde

    Du gehst ja einen anderen Weg, daher schau mal hier, ob diese Einstellungen dir helfen, die Namespaces loszuwerden:

      http://stackoverflow.com/questions/9332558/how-can-i-skip-xml-declaration-when-serializing

    Allerdings weiß ich nicht wirklich, was dich daran stört.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    • Als Antwort markiert Sandra Bauer Freitag, 9. Dezember 2016 16:19
    Mittwoch, 7. Dezember 2016 18:24
    Moderator
  • Hallo Stefan,
    prinzipiell funktioniert Dein Tipp mit dem Replace.
    Problem ist, dass ich dann nicht mehr deserialiseren kann.

    Kurzum, ich habe viel probiert.
    IST: Funktioniert nicht.
    Vielleicht hat jemand bzw. Du noch einen Tipp. Danke.

    Viele Grüße Sandra

    Donnerstag, 15. Dezember 2016 17:26
  • Hallo Sandra,

    wenn Du die XML Datei nur wegen des Entfernens von

    d5p1:nil="true"

    nicht mehr deserialisierbar ist, ist die XML Datei bzw. der XML String entweder nun kaputt oder die Klassendeklaration erfordert diese Angabe zwingend.

    In letzterem Fall kannst Du aber nichts dagegen machen und wirst mit dem Aufbau leben müssen.

    Du solltest aber mal probieren, ob Du mit der Standardserialisierung/-deserialisierung auch solche Probleme hast. Ich hatte dir ja ein paar mal Beispielmethoden gepostet. Nimm die mal für die Tests. Wenn es damit geht, liegt es wohl eher an deiner eigens gebauten Serialisierung.

    Ich verstehe allerdings immer noch nicht, was für ein Problem Du mit den Namespaceangaben hast.

    ---

    Nur als Ergänzung: Ich serialisiere/deserialisiere teils übelst komplexe Objekte/Klassen mit allen möglichen Eigenschaften, Arrays, Listen, untergeordneten Objekten, Attributen, Elemente, usw. Ich hab bisher noch nie solche Probleme gehabt.

    ---

    Um dir bei deinem aktuellen Problem helfen zu können, erstell bitte ein Beispielprojekt mit der Definition aller benötigter Klassen, einer Beispiel XML Datei (bzw. zwei, eine die funktioniert und eben eine, die nicht funktioniert) und natürlich dem kompletten Code, mit dem Du serialisierst und deserialisierst.

    Stell das Projekt dann bitte zum Download zur Verfügung, ich schau mir das dann mal an.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Donnerstag, 15. Dezember 2016 18:13
    Moderator
  • ---

    Um dir bei deinem aktuellen Problem helfen zu können, erstell bitte ein Beispielprojekt mit der Definition aller benötigter Klassen, einer Beispiel XML Datei (bzw. zwei, eine die funktioniert und eben eine, die nicht funktioniert) und natürlich dem kompletten Code, mit dem Du serialisierst und deserialisierst.

    Stell das Projekt dann bitte zum Download zur Verfügung, ich schau mir das dann mal an.



    Hallo Stefan,

    ich hab's Dir zugesendet. Danke im Voraus. 

    Grüße Sandra

    Samstag, 17. Dezember 2016 11:38
  • Hallo Sandra,

    vorab: Da deine Xml Serialisierung irgendwas komisches fabriziert, habe ich meine Standardmethoden ins Projekt integriert und die Aufrufe in den Click Events angepasst.

    public static void SerializeObject<T>(string FileName, T DataObject)
    {
        XmlSerializer Serializer = new XmlSerializer(typeof(T));
        FileStream FileStream = new FileStream(FileName, FileMode.Create);
        XmlTextWriter TextWriter = new XmlTextWriter(FileStream, Encoding.UTF8);
        TextWriter.Indentation = 4;
        TextWriter.IndentChar = ' ';
        TextWriter.Formatting = Formatting.Indented;
    
        XmlSerializerNamespaces XmlNamespace = new XmlSerializerNamespaces();
        XmlNamespace.Add(string.Empty, string.Empty);
    
        Serializer.Serialize(TextWriter, DataObject);
    
        TextWriter.Close();
        FileStream.Close();
        FileStream.Dispose();
    
    }
    
    public static T DeserializeObject<T>(string FileName)
    {
    
        T Result = default(T);
        XmlSerializer Serializer = new XmlSerializer(typeof(T));
        FileStream FileStream = new FileStream(FileName, FileMode.Open, FileAccess.Read);
        XmlTextReader TextReader = new XmlTextReader(FileStream);
        TextReader.Namespaces = true;
    
        Result = (T)Serializer.Deserialize(TextReader);
    
        TextReader.Close();
        FileStream.Close();
        FileStream.Dispose();
    
        return Result;
    
    }

    Die Aufrufe dann wie folgt:

    WebServiceClient.SerializeObject<JobProcessingDataType>( "C:\\Temp\\teSt.XML", Auftrag.GetDummyJobHistoryProcessingData() );

    und:

    JobProcessingDataType test = WebServiceClient.DeserializeObject<JobProcessingDataType>("C:\\Temp\\Test.XML");

    Die Methode "GetDummyJobHistoryProcessingData" ist ein Klon deiner Methode "SaveDummyJobHistoryProcessingData" und gibt nur das Objekt vom Typ "JobProcessingDataType" zurück .

    ---

    Um die Namespace Angaben bei der Serialisierung zu entfernen, kannst Du in der MarkingService.cs die Zeilen:

    [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.A1167.com/schemas/niwip/lm/1")]

    in

    [System.Xml.Serialization.XmlTypeAttribute()]

    ändern oder die Zeilen ganz entfernen. (Bei mir sind es vier Vorkommen)

    Die Deserialisierung klappt dann einwandfrei.

    Eine andere Option sehe ich nicht.

    Wenn Du die Zeilen:

    <Serial xsi:nil="true" />

    in

    <Serial />

    änderst, werden die Daten aber nicht so eingelesen, wie Sie geschrieben wurden. Du hast dann anstatt einem Array mit 10 Elementen und 2 Instanzen sowie 8 null Elementen dann 10 Serial Instanzen im Array, wovon die letzten 8 bei allen Eigenschaften null haben. Aber halt eben anders als das, was weggeschrieben wurde.

    Daher würde ich empfehlen, xsi:nil="true" beizubehalten.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    • Als Antwort markiert Sandra Bauer Samstag, 17. Dezember 2016 17:22
    Samstag, 17. Dezember 2016 12:24
    Moderator
  • Die Deserialisierung klappt dann einwandfrei.

    Eine andere Option sehe ich nicht.

    ..

    änderst, werden die Daten aber nicht so eingelesen, wie Sie geschrieben wurden. Du hast dann anstatt einem Array mit 10 Elementen und 2 Instanzen sowie 8 null Elementen dann 10 Serial Instanzen im Array, wovon die letzten 8 bei allen Eigenschaften null haben. Aber halt eben anders als das, was weggeschrieben wurde.

    Daher würde ich empfehlen, xsi:nil="true" beizubehalten.



    Hallo Stefan,

    ja ok und Danke.

    >Ab .NET Framework 2.0 sollten Sie stattdessen die System.Xml.XmlReader-Klasse verwenden.

    Du nimmst den XmlTextReader und Writer. Da meinte ich mal gelesen zu haben, sei veraltet.

    Aber ja, wenn's damit geht.

    Viele Grüße Sandra


    • Bearbeitet Sandra Bauer Samstag, 17. Dezember 2016 17:22 Format
    Samstag, 17. Dezember 2016 17:21
  • Hallo Sandra,

    Danke für den Hinweis. Hatte ich nicht mehr im Hinterkopf.

    Ich werde dann demnächst mal meine Beispiele auf XmlReader umstellen. Aber läuft ja erstmal auch so.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Samstag, 17. Dezember 2016 19:51
    Moderator
  • Ich werde dann demnächst mal meine Beispiele auf XmlReader umstellen. Aber läuft ja erstmal auch so.



    Hallo Zusammen,

    allen hier noch ein gutes neues Jahr 2017

    @Stefan, kann es sein, dass es dann doch am XmlReader liegt?

    Wenn Du umstellst, kannst ja Bescheid geben.

    Danke und eine schöne Woch.

    Grüße Sandra


    Sonntag, 1. Januar 2017 11:28