Avatar billede Droa Seniormester
18. maj 2017 - 18:07 Der er 12 kommentarer og
2 løsninger

XmlReader Fragment Validering

Hej Eksperter.

Så jeg har et mindre spørgsmål omkring XmlReader og TCP Stream.

Jeg prøver og sende xml hen over en stream, hvor noget af det er vcards, med base64 encodet billeder m.m

Dette overskrider tit de 4096 bytes min socket buffer er på, som siger lidt sig selv.

Problemer er at jeg bruger XmlReader til og Parse Xml Fragmenter ind, hvor jeg manuelt tilføjer dem til mit XmlDocument.

Det betyder når jeg modtager dele af et uafsluttet xmlelement, at XmlReader laver en exception, som os er ret normalt. Men der sker efter jeg allerede har tilføjet de færdige elementer til mit XmlDocument, som gør at næste parsing sker inde i de elementer.

Jeg fixer det lige pt på den måde, at jeg bruger en List<XmlNode> med alle de noder som jerg tilføjer i den fejlede parsing, og derfter sletter dem igen, hvis den rammer en Exception. dog virker det lidt bagvendt. og jeg var nysgerrig om der var bedre måder og Reverte et XmlDocument, hvis der sker en fejl i XmlReader?

Min Alternative løsning var og vente med og tilføje dem til mit XmlDocument, indtil mit try rammer final. men siden jeg bruger XmlDocument, XmlNamespaceManager og XmlParserContext, er der andre ting jeg burde yderligere fjenerne fra de elementer?
Avatar billede arne_v Ekspert
18. maj 2017 - 18:12 #1
Kan du ikke bare give din Stream til din XmlReader og saa laeser den selv flere data naar den har behov for det?
Avatar billede arne_v Ekspert
18. maj 2017 - 18:12 #2
Og hvorfor loader med XmlReader til XmlDocument fremfor direkte til XmlDocument?
Avatar billede Droa Seniormester
18. maj 2017 - 18:31 #3
Xmlen bliver modtaget i SubRoot Elementer

<Root>
<EventX>Test</EventX>
<EventY>Test</EventY>
<EventZ><BinaryBase64>...base64...</BinaryBase64></EventZ>


Root bliver aldrig lukket, før Streamen afslutter, dog vil streamen aldrig afsluttet.
Det gør at XmlReader bare laver fejl. Så jeg har lavet en form for snyd, at hvis buffer.Contains("<Root")
buffer += "</Root>"

Derefter hvorfor jeg ikke bruger XmlDocument.. Det er fordi jeg har brug for at vide hvornår nye Elementer tilføjes, lidt som "Events", jeg ved ikke om XmlDocument, kan lytte til den slags.

klokken: 10:51 Ny <EventU> i <Root>
klokken: 10:52 Ny <EventG> i <Root>
klokken: 12:19 Ny <HeaderUpdate> i <Root>
klokken: 12:22 Ny <HeaderRequest> i <Root>
Avatar billede arne_v Ekspert
18. maj 2017 - 19:17 #4
OK.

Brug for at kende tid => XmlReader til at laese med.

Men jeg stadig ikke se hvorfor du ikke kan lade XmlReader laese fra en stream uendeligt. Den vil vel paent vente paa at de noedvendige data kommer.

Naar stream efter 1 time erller 1 dag eller 1 uge lukker saa kan du naturligvis godt faa en exception p.g.a. manglende slut tag.

Men kunne det ikke fixes med en wrapper stream som returnerede slut tag i det tilfaelde?
Avatar billede Droa Seniormester
18. maj 2017 - 19:37 #5
Jeg bliver nok lige nød til og tjekke om man kan Caste Stream til Sslstream før jeg kan sige om det virker.
Protokollem kræver man kan skifte fra Plain til TLS uden stream lukker, og det har desværre givet problemer med Stream Readers, da de blocker,  og TLS handshake bliver underligt nok modtaget i Readasync og BeginRead, skulle ikke undre mig at Xmlreader gør det samme, men jeg vil lige prøve
Avatar billede arne_v Ekspert
18. maj 2017 - 20:16 #6
Maaske en wrapper stream kan hjaelpe?
Avatar billede Droa Seniormester
18. maj 2017 - 21:05 #7
Du tænker på et ManualResetEvent?
Avatar billede Droa Seniormester
18. maj 2017 - 21:05 #8
I StreamWrapperen
Avatar billede Droa Seniormester
18. maj 2017 - 21:10 #9
Eller hvordan?  Jeg har meget sjældent extended på eller wrapped en Stream, så ved ikke helt hvad overloads der burde arbejdes med,  men jeg tænkte selv et Reset Event der venter hvis server springer til en Sslstream
Avatar billede arne_v Ekspert
19. maj 2017 - 01:58 #10
Jeg har lidt svaert ved at gennemskue praecis hva det er du goer.

Men her er lidt inspiration:


using System;
using System.IO;
using System.Text;
using System.Xml;

namespace E
{
    public class ManipulateStream : Stream
    {
        private Stream real;
        public ManipulateStream(Stream real)
        {
            this.real = real;
        }
       
        public override void Write(byte[] buffer, int offset, int count)
        {
            real.Write(buffer, offset, count);
        }
       
        public override void SetLength(long value)
        {
            real.SetLength(value);
        }
       
        public override long Seek(long offset, SeekOrigin origin)
        {
            return real.Seek(offset, origin);
        }
       
        public override int Read(byte[] buffer, int offset, int count)
        {
            //return real.Read(buffer, offset, count);
            byte[] buffer2 = new Byte[count];
            int res = real.Read(buffer2, 0, count);
            if(res > 0)
            {
                string tmp = Encoding.UTF8.GetString(buffer2, 0, count);
                Console.WriteLine("read : {0}", tmp);
            }
            else
            {
                Console.WriteLine("read EOF");
            }
            Array.Copy(buffer2, buffer, res);
            return res;
        }
       
        public override long Position {
            get
            {
                return real.Position;
            }
            set
            {
                real.Position = value;
            }
        }
       
        public override long Length {
            get
            {
                return real.Length;
            }
        }
       
        public override void Flush()
        {
            real.Flush();
        }
       
        public override bool CanWrite {
            get
            {
                return real.CanWrite;
            }
        }
       
        public override bool CanSeek {
            get
            {
                return real.CanSeek;
            }
        }
       
        public override bool CanRead {
            get
            {
                return real.CanRead;
            }
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            string s = "<all><one>A</one><one>BB</one><one>CCC</one></all>";
            byte[] b = Encoding.UTF8.GetBytes(s);
            //Stream stm = new MemoryStream(b);
            Stream stm = new ManipulateStream(new MemoryStream(b));
            XmlReader xr = XmlReader.Create(stm);
            while(xr.Read())
            {
                if(xr.NodeType == XmlNodeType.Element)
                {
                    Console.WriteLine("element : {0}", xr.Name);
                }
            }
            Console.ReadKey();
        }
    }
}
Avatar billede Droa Seniormester
20. maj 2017 - 09:57 #11
Dette burde virke, jeg kan altid lave en Methode som denne...

public void StartTLS(X509Certificate2 cert){
  SslStream SecureStream = new SslStream(real, true);
  SecureStream.AuthenticateAsServer(cert, false, System.Security.Authentication.SslProtocols.Tls, true);
  real = SecureStream;
}

siden det køre i samme tråd med reader, kan man køre dette uden problemer tror jeg :)
Avatar billede Droa Seniormester
20. maj 2017 - 09:57 #12
i dit ManipulateStream exempel
Avatar billede arne_v Ekspert
21. maj 2017 - 03:26 #13
Hvis den grundliggende teknik virker saa boer det ogsaa virke med wrapper stream.

Det er muligvis vigtigt at undgaa at den original stream bufferer input.
Avatar billede Droa Seniormester
21. maj 2017 - 09:59 #14
det er så lidt det jeg lige skal prøve og finde ud af hvad der er best, fordi på en enkelt tråd er det jo let, da .Read ikke bliver læst igen før den starter forfra i løkken, men i en multi-tråd er det jo noget med nogen ResetEvents, der  skal nulstilles.

Før brugte jeg BlockingCollectiongs til og pipeline mine data igennem parser og derefter til "handlings tråden" der udførte handlinger på serveren. men det var låst af med en ren form af spegetti kode, der låste af for Read indtil alle handlinger var færdige, Lidt som en "Stream throttle" så jeg kun fik en (eller mindre) XmlRoot Children af gangen.
Det har dog virket indtil nu, men jeg er sikker på den kan hænge i scenarier, da jeg simpelt nok bare tjekker om de BlockingCollections ikke har nogen items i sig, før den åbner op for Read igen.


...
Server: <offers><tls /><sasl /></offer>
Client: <starttls />
Server: <proceed>
Client: *tls handskake*
Server: *tls authendicate*
if Success
Server: <offers><sasl /></offer>
Client: <auth type="sasl"><mechanism>SCRAM-1</mechanism></auth>
if Not Success
Server: <error>TLS Failure</error>
Server: *terminate socket*
...
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester