1

This hangs application:

XPathDocument xPathDocument = new XPathDocument(networkStream);

I think this is due to XPathDocument is still waiting for data, but how to prevent it?

Milek7
  • 157
  • 1
  • 10
  • What do you want exactly? XPathDocument(...) has to wait until the whole XML data has been received to create a valid XPathDocument object, right? –  Aug 01 '14 at 10:01
  • @Atomosk: what will it help? application will not stop, but XML will still not ready. – Milek7 Aug 01 '14 at 10:10
  • @elgonzo: Yes. ​​​​​​​​​​​​​​​​​​​​​​​​​ – Milek7 Aug 01 '14 at 10:10
  • The XPathDocument will be ready when it is ready - that means when it has pulled all data from the server. There is no XPathDocument object in existence until `xPathDocument = new XPathDocument(networkStream);` has been executed. Delegating this code to a background thread/task will prevent freezing your UI, but it will obviously not create `xPathDocument` immediately out of thin air. Your problem is rather with your software design, not so much with the code line in your question. Helping you is difficult without understanding how/where you need to use `xPathDocument`... –  Aug 01 '14 at 10:14
  • @elgonzo: I know this. But `xPathDocument = new XPathDocument(networkStream);` didn't end executing even whole XML from server is received. I get this to working by reading NetworkStream to string and creating StringReader, but I do not like this solution. – Milek7 Aug 01 '14 at 10:20
  • That is odd. How do you know the whole XML has been received by the client side, do you just guess/believe it? While there might be other reasons, i would guess the server keeps the connection open, making the TCP client and the networkstream (and thus the XPathDocument constructor) believe that more data might be sent by the server. What kind of server is your software communicating with? –  Aug 01 '14 at 10:28
  • If it receive root element ending, whole XML is received. Yes, server keeps the connection open, for future communication. – Milek7 Aug 01 '14 at 10:33
  • "*server keeps the connection open*" is the likely cause for your problem. Forget a moment about `XPathDocument` -- how would the client generally know when the server finished sending data while the connection stays open? Do you assume that client should know that because it received the closing XML root tag, or is there some other indication that allows the client to know when all data has been received? –  Aug 01 '14 at 10:55
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/58482/discussion-between-milek7-and-elgonzo). – Milek7 Aug 01 '14 at 11:05

1 Answers1

2

Due to server didn't close connection after sending whole XML (connection remaining open for future communication) XPathDocument still waits for data. Server does not provide any other data to determine if XML transfer is completed. However it is possible to check is whole XML is received by root tag ending. XPathDocument dosen't look for root tag ending, so this solution is bit tricky, but works. I reading stream using XmlReader and reproduce XML by XmlWriter which writes in StringWriter. At end string output from StringWriter is suppiled to StringReader, which is read by XmlReader. And finnaly, XPathDocument reads data from this XmlReader. Here is example code:

        XmlReader xmlReader = XmlReader.Create(networkStream);
        StringWriter stringWriter = new StringWriter();
        XmlWriter xmlReadBuffer = XmlWriter.Create(stringWriter);

        while (xmlReader.Read())
        {
            switch (xmlReader.NodeType)
            {
                case XmlNodeType.XmlDeclaration:
                    xmlReadBuffer.WriteStartDocument();
                    break;
                case XmlNodeType.Element:
                    xmlReadBuffer.WriteStartElement(xmlReader.Name);
                    if (xmlReader.HasAttributes)
                        xmlReadBuffer.WriteAttributes(xmlReader, false);
                    if (xmlReader.IsEmptyElement)
                        goto case XmlNodeType.EndElement;
                    break;
                case XmlNodeType.EndElement:
                    if (xmlReader.Depth == 0)
                    {
                        xmlReadBuffer.WriteEndElement();
                        xmlReadBuffer.WriteEndDocument();
                        goto EndXml;
                    }
                    xmlReadBuffer.WriteEndElement();
                    break;
                case XmlNodeType.Text:
                    xmlReadBuffer.WriteString(xmlReader.Value);
                    break;
                default:
                    break;
            }
        }

    EndXml:
    xmlReadBuffer.Flush();

    XPathDocument xPathDocument = new XPathDocument(XmlReader.Create(new StringReader(stringWriter.ToString())));

Big thanks for elgonzo who pointed me to this.

Community
  • 1
  • 1
Milek7
  • 157
  • 1
  • 10
  • I knew you could do it :) Your solution turned out to be somewhat shorter than i expected when we talked yesterday in chat. The amount of code necessary for this 'workaround' is quite tolerable, actually... –  Aug 01 '14 at 23:44