If you always had to upload large volumes of data over HTTP, you lot probably ran into timeout issues. The default Timeout value for HttpWebRequest is 100 seconds, which means that if it takes more than that from the time y'all send the asking headers to the time you receive the response headers, your asking will fail. Obviously, if you're uploading a big file, you need to increase that timeout… just to which value?

If you know the bachelor bandwidth, yous could calculate a crude judge of how long it should have to upload the file, simply it's not very reliable, because if there is some network congestion, it will have longer, and your asking volition neglect even though information technology could have succeeded given enough time. And then, should you ready the timeout to a very large value, like several hours, or even Timeout.Infinite? Probably not. The most compelling reason is that even though the transfer itself could have hours, some phases of the commutation shouldn't accept that long. Let's decompose the phases of an HTTP upload:

timeout1

Obtaining the request stream or getting the response (orange parts) isn't supposed to take very long, and then obviously nosotros demand a rather short timeout there (the default value of 100 seconds seems reasonable). But sending the request body (blue office) could have much longer, and there is no reliable style to decide how long that should be; as long as we go along sending data and the server is receiving it, at that place is no reason not to continue, even if it'southward taking hours. And then nosotros really don't desire a timeout at all at that place! Unfortunately, the behavior of the Timeout property is to consider everything from the phone call to GetRequestStream to the return of GetResponse

In my opinion, it's a blueprint flaw of the HttpWebRequest class, and i that has bothered me for a very long time. So I eventually came up with a solution. It relies on the fact that the asynchronous versions of GetRequestStream and GetResponse don't accept a timeout machinery. Hither'southward what the documentation says:

*The Timeout property has no effect on asynchronous requests made with the BeginGetResponse or BeginGetRequestStream method.*In the case of asynchronous requests, the client application implements its own fourth dimension-out mechanism. Refer to the case in the BeginGetResponse method.

Then, a solution could be to to use these methods directly (or the new Task-based versions: GetRequestStreamAsync and GetResponseAsync); but more often than not, you already have an existing code base that uses the synchronous methods, and changing the lawmaking to brand it fully asynchronous is unremarkably not niggling. So, the easy approach is to create synchronous wrappers around BeginGetRequestStream and BeginGetResponse, with a way to specify a timeout for these operations:

                                      public                    static                    form                    WebRequestExtensions                    {                    public                    static                    Stream GetRequestStreamWithTimeout(                    this                    WebRequest request,                    int?                    millisecondsTimeout =                    null)     {                    return                    AsyncToSyncWithTimeout(             request.BeginGetRequestStream,             request.EndGetRequestStream,             millisecondsTimeout ?? request.Timeout);     }                    public                    static                    WebResponse GetResponseWithTimeout(                    this                    HttpWebRequest request,                    int?                    millisecondsTimeout =                    nil)     {                    return                    AsyncToSyncWithTimeout(             request.BeginGetResponse,             request.EndGetResponse,             millisecondsTimeout ?? request.Timeout);     }                    private                    static                    T AsyncToSyncWithTimeout<T>(         Func<AsyncCallback,                    object, IAsyncResult> begin,         Func<IAsyncResult, T> end,                    int                    millisecondsTimeout)     {                    var                    iar = begin(null,                    null);                    if                    (!iar.AsyncWaitHandle.WaitOne(millisecondsTimeout))         {                    var                    ex =                    new                    TimeoutException();                    throw                    new                    WebException(ex.Bulletin, ex, WebExceptionStatus.Timeout,                    null);         }                    return                    end(iar);     } }                                  

(note that I used the Begin/End methods rather than the Async methods, in order to keep compatibility with older versions of .NET)

These extension methods tin be used instead of GetRequestStream and GetResponse; each of them will timeout if they take besides long, but in one case you have the request stream, you can take equally long as you want to upload the information. Notation that the stream itself has its own read and write timeout (5 minutes past default), so if v minutes go by without any information existence uploaded, the Write method will crusade an exception. Here is the new upload scenario using these methods:

timeout2

Every bit you tin can encounter, the only divergence is that the timeout doesn't utilise anymore to the transfer of the request body, but only to obtaining the request stream and getting the response. Here's a full example that corresponds to the scenario to a higher place:

                                      long                    UploadFile(string                    path,                    string                    url,                    string                    contentType) {                    // Build request                                                            var                    asking = (HttpWebRequest)WebRequest.Create(url);     request.Method = WebRequestMethods.Http.Post;     request.AllowWriteStreamBuffering =                    simulated;     request.ContentType = contentType;                    string                    fileName = Path.GetFileName(path);     request.Headers["Content-Disposition"] =                    string.Format("zipper; filename=\"{0}\"", fileName);                    try                    {                    // Open source file                                                            using                    (var                    fileStream = File.OpenRead(path))         {                    // Set content length based on source file length                                                            request.ContentLength = fileStream.Length;                    // Get the request stream with the default timeout                                                            using                    (var                    requestStream = request.GetRequestStreamWithTimeout())             {                    // Upload the file with no timeout                                                            fileStream.CopyTo(requestStream);             }         }                    // Get response with the default timeout, and parse the response trunk                                                            using                    (var                    response = request.GetResponseWithTimeout())                    using                    (var                    responseStream = response.GetResponseStream())                    using                    (var                    reader =                    new                    StreamReader(responseStream))         {                    cord                    json = reader.ReadToEnd();                    var                    j = JObject.Parse(json);                    return                    j.Value<long>("Id");         }     }                    grab                    (WebException ex)     {                    if                    (ex.Status == WebExceptionStatus.Timeout)         {             LogError(ex,                    "Timeout while uploading '{0}'", fileName);         }                    else                    {             LogError(ex,                    "Mistake while uploading '{0}'", fileName);         }                    throw;     } }                                  

I hope you volition detect this helpful!