-6

I was passing a large file in the first arg to SendXMLFile() below but, since it was causing the handheld device to "hang"/"freeze" I temporarily hard-coded a much smaller file (3 KB as opposed to 1121 KB) for testing.

The file does indeed exist (in the same folder as the .exe/.dll), as can be seen by this code:

// test with smaller file:
fileName = "DSD_v6666_3_20140310140737916.xml";
MessageBox.Show("Made it before file.Open");
using (FileStream fileTest = File.Open(fileName, FileMode.CreateNew)) 
{
    fileTest.Write(info, 0, info.Length);
    fileTest.Flush();
}
if (!File.Exists(fileName))
{
    MessageBox.Show(String.Format("{0} does not seem to exist", fileName));
} 
else
{
    MessageBox.Show(String.Format("{0} DOES seem to exist", fileName));
}

string justFileName = Path.GetFileNameWithoutExtension(fileName);
String uri = String.Format(@"http://SHANNON2:21609/api/inventory/sendXML/gus/woodrow/{0}", justFileName).Trim();
SendXMLFile(fileName, uri, 500);

Here is the code that is then called, attempting to send the file:

public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
    // TODO: Remove after testing
    String s = String.Format("xmlFilepath == {0}, uri == {1}, timeout == {2}", xmlFilepath, uri, timeout);
    MessageBox.Show(s);
    // </ TODO: Remove after testing

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);

    //request.KeepAlive = false; // should this be true? <== commented out as a test, but no diff in behavior
    request.ProtocolVersion = HttpVersion.Version10;
    request.ContentType = "application/xml";
    request.Method = "POST";

    StringBuilder sb = new StringBuilder();
    // TODO: Remove after testing
    MessageBox.Show("Made it to just before the StreamReader using");
    using (StreamReader sr = new StreamReader(xmlFilepath))
    {
        // TODO: Remove after testing
        MessageBox.Show("Made it just inside the StreamReader using"); // <= This is the last point reached 
        String line;
        while ((line = sr.ReadLine()) != null)
        {
            // TODO: Remove after testing
            MessageBox.Show(string.Format("line == {0}", line));
            sb.Append("\r\n");
        }
        . . .

When I run this, I see:

"Made it before file.Open"
"DSD_v6666_3_20140310140737916.xml DOES seem to exist"
[The xmlFilepath, uri, and timout vals expected]
"Made it to just before the StreamReader using"
"Made it just inside the StreamReader using"

-- but not the "line == ..." message - it hangs, and I have to warm boot the device to bring it back from electronic limbo.

Is there a potential problem with the StreamReader code, or...???

UPDATE

I don't know whether this is a problem is in the data, or a differences I had to make in the code to get it to work in the Compact Framework. I have very similar code that works from a Winforms app:

public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);

    request.KeepAlive = false;
    request.ProtocolVersion = HttpVersion.Version10;
    request.ContentType = "application/xml";
    request.Method = "POST";

    StringBuilder sb = new StringBuilder();
    using (StreamReader sr = new StreamReader(xmlFilepath))
    {
        String line;
        while ((line = sr.ReadLine()) != null)
        {
            sb.AppendLine(line);
        }
        byte[] postBytes = Encoding.UTF8.GetBytes(sb.ToString());

        if (timeout < 0)
        {
            request.ReadWriteTimeout = timeout;
            request.Timeout = timeout;
        }

        request.ContentLength = postBytes.Length;

        try
        {
            Stream requestStream = request.GetRequestStream();

            requestStream.Write(postBytes, 0, postBytes.Length);
            requestStream.Close();

            //using (var response = (HttpWebResponse)request.GetResponse())
            //{
            //    return response.ToString();
            //}
            // alternate way, safe for older versions of .NET
            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse(); 
            }
            finally
            {
                IDisposable disposableResponse = response as IDisposable;
                if (disposableResponse != null) disposableResponse.Dispose();
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
            request.Abort();
            return string.Empty;
        }
    }
}

---called like so, passing the same file as a test case:

private void button20_Click(object sender, EventArgs e)
{
    // Change the file name before each test
    String fullFilePath = @"C:\HoldingTank\DSD_v6666_3_20140310140737916.xml";
    string justFileName = Path.GetFileNameWithoutExtension(fullFilePath);
    String uri = String.Format(@"http://localhost:21608/api/inventory/sendXML/su/su/{0}", justFileName);
    SendXMLFile(fullFilePath, uri, 500);
}

UPDATE 2

I changed the code to use an XMLTextReader, and now I'm back to the err I was previously having, namely "(400) Bad Request" which is documented in most of its gory detail here.

Here is the new code, and what I now see:

public static bool WriteIt2( string fileName, string data, long fsize ) { bool retVal = false; int bytRd = 0; // if use this, change its name string the_Msg = "";

if (File.Exists(fileName))
{
    File.Delete(fileName);
}

Byte[] info = Encoding.UTF8.GetBytes(data);
// Testing with this relatively small file for now
fileName = "DSD_v6666_3_20140310140737916.xml";
MessageBox.Show("Made it before file.Open");
using (FileStream fileTest = File.Open(fileName, FileMode.CreateNew)) 
{
    fileTest.Write(info, 0, info.Length);
    fileTest.Flush();
}
if (!File.Exists(fileName))
{
    MessageBox.Show(String.Format("{0} does not seem to exist", fileName));
} // I have never seen the msg above, but always saw the one below, so commented it out
else //<= always exists, so unnecessary
{
    MessageBox.Show(String.Format("{0} DOES seem to exist", fileName));
}

string justFileName = Path.GetFileNameWithoutExtension(fileName);
String uri = String.Format(@"http://SHANNON2:21609/api/inventory/sendXML/su/su/{0}", justFileName).Trim();

SendXMLFile(fileName, uri, 500);

Now here's the code that actually does the reading, writing, and sending (or tries to):

public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
    String s = String.Format("xmlFilepath == {0}, uri == {1}, timeout == {2}", xmlFilepath, uri, timeout);
    MessageBox.Show(s);
    // </ TODO: Remove after testing

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);

    request.ProtocolVersion = HttpVersion.Version10;
    request.ContentType = "application/xml";
    request.Method = "POST";

    StringBuilder sb = new StringBuilder();
    MessageBox.Show("Made it to just before the StreamReader using");

    StreamReader sr = new StreamReader(xmlFilepath);
    MessageBox.Show("Made it past the StreamReader being constructed");
    XmlTextReader reader = null;    
    reader = new XmlTextReader(sr);
    while (reader.Read()) 
    {
        switch (reader.NodeType) 
        {
            case XmlNodeType.Element: // The node is an Element.
                sb.Append("<" + reader.Name);
            while (reader.MoveToNextAttribute()) // Read attributes.
                sb.Append(" " + reader.Name + "='" + reader.Value + "'");
                sb.Append(">");
                sb.Append(">");
                break;
            case XmlNodeType.Text: //Display the text in each element.
                sb.Append (reader.Value);
                break;
            case XmlNodeType. EndElement: //Display end of element.
                sb.Append("</" + reader.Name);
                sb.Append(">");
                break;
        }
    }
    // TODO: Remove after testing
    MessageBox.Show("Made it past the while loop");
    MessageBox.Show(String.Format("sb first line is {0}", sb[0].ToString()));
    MessageBox.Show(String.Format("sb tenth line is {0}", sb[9].ToString()));
    byte[] postBytes = Encoding.UTF8.GetBytes(sb.ToString());

    if (timeout < 0)
    {
        request.Timeout = timeout;
    }

    request.ContentLength = postBytes.Length;

    try
    {
        Stream requestStream = request.GetRequestStream();

        requestStream.Write(postBytes, 0, postBytes.Length);
        requestStream.Close();

        // This code for older versions of .NET from ctacke:
        HttpWebResponse response = null;
        try
        {
            response = (HttpWebResponse)request.GetResponse();
            return response.ToString();
        }
        finally
        {
            IDisposable disposableResponse = response as IDisposable;
            if (disposableResponse != null) disposableResponse.Dispose();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
        request.Abort();
        return string.Empty;
    }
}

What I see now when this runs:

0) "Made it before file.Open"
1) "DSD_v6666_3_20140310140737916.xml DOES seem to exist"
2) [ the xmlFilePath and other args - they are what is expected ]
3) "Made it to just before the StreamReader using"
4) "Made it past the StreamReader being constructed
5) "Made it past the while loop
6) "sb first line is "<"
7) "sb tenth line is ">"
8) "The remote server returned an error (400) Bad Request"

So at least it's no longer hanging, but I'm back to wondering why the server considers this a bad request.

Community
  • 1
  • 1
B. Clay Shannon-B. Crow Raven
  • 8,547
  • 144
  • 472
  • 862
  • 1
    Does the file has anything in it? I suspect it is an empty file. – Sriram Sakthivel Aug 28 '14 at 21:04
  • 1
    What do you see when stepping into that `while`? – admdrew Aug 28 '14 at 21:04
  • Is an exception being thrown? – Cameron Aug 28 '14 at 21:04
  • 1
    It would be interesting to know what do you write in that file at the beginning. And could you explain why you use a binary write and then try to read it back with StreamReader.ReadLine? – Steve Aug 28 '14 at 21:10
  • 1
    Put another messagebox after thw while loop. It probably gets straight there, because `line` is null (empty file as @SriramSakthivel commented above). – Reg Edit Aug 28 '14 at 21:15
  • Another possibility could be: What if file contains sequence of characters and no new line character `\n` ? If the file is very huge, as you noticed `ReadLine` will block till it finds `\n`. If the file is very huge then you might feel it is frozen. – Sriram Sakthivel Aug 28 '14 at 21:23
  • @SriramSakthivel: The file is not empty; as I mention, it is 3KB – B. Clay Shannon-B. Crow Raven Aug 28 '14 at 21:25
  • @admdrew: I cannot step into it; that's why there are all those debug strings - I have to copy the .exe to the device and run it directly each time I make a change. – B. Clay Shannon-B. Crow Raven Aug 28 '14 at 21:26
  • @Cameron: Not that I see - it just hangs/freezes ("hangs ice" instead of "hanging fire" I reckon). – B. Clay Shannon-B. Crow Raven Aug 28 '14 at 21:27
  • Related? https://connect.microsoft.com/VisualStudio/feedback/details/519059/streamreader-readline-causes-timeouts-on-some-stream-classes-when-only-carriage-returns-are-used – Steve Aug 28 '14 at 21:28
  • @Steve: If you mind, what is the first line in the file, it is: – B. Clay Shannon-B. Crow Raven Aug 28 '14 at 21:28
  • 1
    @B.ClayShannon What you're doing isn't specific to whatever device you're developing for. What sort of behavior do you see when you test this in your development environment? – admdrew Aug 28 '14 at 21:30
  • 1
    Yes in an XML files that's usually the first line, but I fail to see what this could cause the hang. You are not using XML classes and methods here. – Steve Aug 28 '14 at 21:32
  • @Stave: I meant, "if you mean what is..." – B. Clay Shannon-B. Crow Raven Aug 28 '14 at 21:33
  • 1
    What device, what is `info`, how are line-breaks encoded (`\n` or `\r\n`) and what is `Envonment.NewLine` on that device? – H H Aug 28 '14 at 21:46
  • @HenkHolterman: The device is a Motorola 3190; "info" is a byte array that is assigned the string data (which is to be the file contents): Byte[] info = Encoding.UTF8.GetBytes(data); – B. Clay Shannon-B. Crow Raven Aug 28 '14 at 21:54
  • And what are the line-breaks in `data` ? I'm suspecting `\n` and then if the device expects `\r\n` the ReadLine would indeed hang. – H H Aug 28 '14 at 22:02
  • @HenkHolterman: I don't know what the line breaks are in data (I haven't discovered the part of this obfuscated code where that is done); I also don't know what the device expects. – B. Clay Shannon-B. Crow Raven Aug 28 '14 at 22:21
  • You will have to find out then. More MessageBoxes. Or reimplement it in a way that is not line oriented. – H H Aug 28 '14 at 23:14
  • @HenkHolterman: With Update 2's code, I am back to getting an err response from the server (400), but apparently using the xml reader is necessary for this older version of .NET (the previous code works fine in a modern WinForms app). Not "modern" as in Windows 8, but as in .NET 4.5.1 / Windows 7 / Visual Studio 2013. – B. Clay Shannon-B. Crow Raven Aug 28 '14 at 23:19
  • 2
    I see no reason to use an XmlReader. The Reader/StringBuilder code probably maims the Xml to something invalid. Why do (you think) you needa all that? The File is a Stream, the request needs a Stream. Done. – H H Aug 28 '14 at 23:29
  • @HenkHolterman: This sounds intriguing, because it sounds like a simplification, and I always prefer the simplest possible solution, but I would need something more specific. IOW: how exactly would I do that - what in the code above can be removed? I tried / experimented with various things, but they all either didn't compile at all, or didn't work any better than what I've already experienced ("The remote server returned an error: (400) Bad Request.") – B. Clay Shannon-B. Crow Raven Aug 29 '14 at 23:24

1 Answers1

2

I think you should return to basics:

public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
    using (var client = new WebClient())
    {                
        client.Headers.Add("Content-Type", "application/xml");                
        byte[] response = client.UploadFile(uri, "POST", xmlFilepath);
        return Encoding.ASCII.GetString(response);
    }
}

and see what works and what the server thinks of your file.

When you really need a TimeOut then see this answer

Community
  • 1
  • 1
H H
  • 263,252
  • 30
  • 330
  • 514