tags:

views:

1269

answers:

6

We've got a .NET 2.0 WinForms app that needs to upload files to an IIS6 Server via WebDav. From time to time we get complaints from a remote office that they get one of the following error messages

  • The underlying connection was closed: an unexpected error occurred on send.
  • The underlying connection was closed: an unexpected error occurred on receive.

This only seems to occur with large files (~20Mb plus). I've tested it with a 40Mb file from my home computer and tried putting 'Sleep's in the loop to simulate a slow connection so I suspect that it's down to network issues at their end... but

  1. The IT at the remote office are no help
  2. I'd like to rule out the posibility my code is at fault.

So - can anybody spot any misakes or suggest any workarounds that might 'bulletproof' the code against this problem. Thanks for any help. Chopped down version of code follows:

    public bool UploadFile(string localFile, string uploadUrl)
    {
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uploadUrl);

        try
        {
            req.Method = "PUT";
            req.AllowWriteStreamBuffering = true;
            req.UseDefaultCredentials = Program.WebService.UseDefaultCredentials;
            req.Credentials = Program.WebService.Credentials;
            req.SendChunked = false;
            req.KeepAlive = true;
            Stream reqStream = req.GetRequestStream();
            FileStream rdr = new FileStream(localFile, FileMode.Open, FileAccess.Read);
            byte[] inData = new byte[4096];
            int bytesRead = rdr.Read(inData, 0, inData.Length);

            while (bytesRead > 0)
            {
                reqStream.Write(inData, 0, bytesRead);
                bytesRead = rdr.Read(inData, 0, inData.Length);
            }

            reqStream.Close();
            rdr.Close();

            System.Net.HttpWebResponse response = (HttpWebResponse)req.GetResponse();
            if (response.StatusCode != HttpStatusCode.OK && response.StatusCode!=HttpStatusCode.Created)
            {
                MessageBox.Show("Couldn't upload file");
                return false;
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
            return false;
        }
        return true;
    }
A: 

The size of the uploads might be limited.

See here for one discussion: http://www.codeproject.com/KB/aspnet/uploadlargefilesaspnet.aspx

david valentine
It's not that, WebDAV transfers don't hit ASP.NET and I can upload the same file myself from a different remote netowrk.
SillyMonkey
+1  A: 

Maybe try using POST, but the real culprit is probably the content type.

Try setting

req.ContentType = "application/octet-stream";
req.ContentLength = inData.Length;

or look at the code in the accepted answer here: http://stackoverflow.com/questions/566462/upload-files-with-httpwebrequest-multipart-form-data

Both my example and the link I provided involve modifying the ContentType - my example is simpler but might not work, as most applications receiving files expect multipart

Luke Schafer
This wouldn't cause an intermittent problem.
David
+3  A: 

Try setting KeepAlive to false:

req.KeepAlive = false;

This will allow the connection to be closed and opened again. It will not allow to use a persistent connection. I found a lot of references in the Web that suggested this in order to solve a similar to yours error. This is a relevant link.

Anyway, it is not a good idea to use HTTP PUT (or HTTP POST) to upload large files. It will be better to use FTP or a download/upload manager. These will handle retries, connection problems, timeouts automatically for you. The upload will be faster too and you could also resume a stopped uploading. If you decide to stay with HTTP, you should at least try to add a retry mechanism. If an upload is taking too long, then there is a high probability that it will fail due to proxy, server timeout, firewall or what ever reason not to have with your code.

kgiannakakis
+3  A: 

To remove the risk of a bug in your code, try using WebClient:

using (WebClient client = new WebClient())
{
    client.UseDefaultCredentials = Program.WebService.UseDefaultCredentials;
    client.Credentials = Program.WebService.Credentials;
    client.UploadFile(uploadUrl, "PUT", localFile);
}
Marc Gravell
Must the URL include the target filename?
JL
I would expect so, but it will depend on the server.
Marc Gravell
A: 

Start by checking some basic configuration. The default values of either of the following may cause problems in file upload - including termination of the connection. I believe IIS 6 would never allow file upload > 2GB (even if it could complete, regardless of config). Msdn describes these nicely.

<httpRuntime executionTimeout = "30"  maxRequestLength="200"/>

EDIT: This is ASP.NET config, of course, which assumes you are running your own webdav server or a 3rd party server within ASP.NET. If it's a different webdav server, you'll want to look for the equivalent.

Precipitous
+1  A: 

Please you check whether [Enable Http Keep-Alives] is set [on] at [Web Site] tab in IIS manager.

sesame