/// <summary> /// Uploads file /// </summary> /// <typeparam name="R">Result type</typeparam> /// <param name="method">HTTP method</param> /// <param name="url">URL for request</param> /// <param name="file">File upload parameters. Input stream must support Length</param> /// <returns>Async result object</returns> public async Task <R> SendFile <R>(HttpMethod method, string url, SendFileInfo file) { R result = default(R); await Retry.Do( RetryTimes, RetryDelay, async() => { var client = await GetHttpClient(url).ConfigureAwait(false); try { client.Method = method.ToString(); client.AllowWriteStreamBuffering = false; string boundry = Guid.NewGuid().ToString(); client.ContentType = $"multipart/form-data; boundary={boundry}"; client.SendChunked = true; using (var input = file.StreamOpener()) { var pre = GetMultipartFormPre(file, input.Length, boundry); var post = GetMultipartFormPost(boundry); client.ContentLength = pre.Length + input.Length + post.Length; using (var output = await client.GetRequestStreamAsync().ConfigureAwait(false)) { if (file.CancellationToken != null) { var token = (CancellationToken)file.CancellationToken; await pre.CopyToAsync(output, 81920).ConfigureAwait(false); //await input.CopyToAsync(output, 81920).ConfigureAwait(false); await CopyToStreamAsync(input, output, 81920, token, file.Progress).ConfigureAwait(false); if (token.IsCancellationRequested) { client.Abort(); throw new OperationCanceledException(token); } await post.CopyToAsync(output, 81920).ConfigureAwait(false); } else { await pre.CopyToAsync(output).ConfigureAwait(false); await input.CopyToAsync(output).ConfigureAwait(false); await post.CopyToAsync(output).ConfigureAwait(false); } } } using (var response = (HttpWebResponse)await client.GetResponseAsync().ConfigureAwait(false)) { if (!response.IsSuccessStatusCode()) { return(await LogBadResponse(response).ConfigureAwait(false)); } result = await response.ReadAsAsync <R>().ConfigureAwait(false); } return(true); } catch (Exception) { client.Abort(); throw; } }, GeneralExceptionProcessor).ConfigureAwait(false); return(result); }