/// <summary> /// Parses an error response and wraps all the information in it into a ClientException. /// </summary> /// <param name="ex">Original web exception.</param> /// <param name="requestUrl">Request url that caused the web exception.</param> /// <param name="method">Http method (e.g GET or POST)</param> /// <param name="body">Request body.</param> /// <returns>A client exception that contains parsed server info (e.g. OData exception type, /// status code, original response text, etc.) and the original exception as an inner exception.</returns> public static Task <ClientException> GetClientExceptionAsync(HttpRequestException ex, string requestUrl = null, HttpMethod method = null, string body = null) { var ce = new ClientException("A request exception occured.", ex) { Response = string.Empty }; ce.Data["Url"] = requestUrl; ce.Data["Method"] = method?.Method ?? HttpMethod.Get.Method; ce.Data["Body"] = body; return(Task.FromResult(ce)); }
//============================================================================= Helper methods /// <summary> /// Parses an error response and wraps all the information in it into a ClientException. /// </summary> /// <param name="ex">Original web exception.</param> /// <param name="requestUrl">Request url that caused the web exception.</param> /// <param name="method">Http method (e.g GET or POST)</param> /// <param name="body">Request body.</param> /// <returns>A client exception that contains parsed server info (e.g. OData exception type, /// status code, original response text, etc.) and the original exception as an inner exception.</returns> public static async Task <ClientException> GetClientExceptionAsync(WebException ex, string requestUrl = null, HttpMethod method = null, string body = null) { var responseString = await ReadResponseStringAsync(ex.Response); var exceptionData = GetExceptionData(responseString); var ce = new ClientException(exceptionData, ex) { Response = responseString }; ce.Data["Url"] = requestUrl; ce.Data["Method"] = method?.Method ?? HttpMethod.Get.Method; ce.Data["Body"] = body; return(ce); }
private static async Task <Content> UploadInternalAsync(Stream binaryStream, UploadData uploadData, ODataRequest requestData, ServerContext server = null, Action <int> progressCallback = null) { // force set values uploadData.UseChunk = binaryStream.Length > ClientContext.Current.ChunkSizeInBytes; if (uploadData.FileLength == 0) { uploadData.FileLength = binaryStream.Length; } requestData.Parameters["create"] = "1"; dynamic uploadedContent = null; var retryCount = 0; // send initial request while (retryCount < REQUEST_RETRY_COUNT) { try { var myReq = CreateInitUploadWebRequest(requestData.ToString(), server, uploadData); SnTrace.Category(ClientContext.TraceCategory).Write("###>REQ: {0}", myReq.RequestUri); using (var wr = await myReq.GetResponseAsync()) { uploadData.ChunkToken = await ReadResponseStringAsync(wr); } // succesful request: skip out from retry loop break; } catch (WebException ex) { if (retryCount >= REQUEST_RETRY_COUNT - 1) { var ce = new ClientException("Error during binary upload.", ex); ce.Data["SiteUrl"] = requestData.SiteUrl; ce.Data["Parent"] = requestData.ContentId != 0 ? requestData.ContentId.ToString() : requestData.Path; ce.Data["FileName"] = uploadData.FileName; ce.Data["ContentType"] = uploadData.ContentType; throw ce; } else { Thread.Sleep(50); } } retryCount++; } var boundary = "---------------------------" + DateTime.UtcNow.Ticks.ToString("x"); var trailer = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n"); // send subsequent requests var buffer = new byte[ClientContext.Current.ChunkSizeInBytes]; int bytesRead; var start = 0; // reuse previous request data, but remove unnecessary parameters requestData.Parameters.Remove("create"); while ((bytesRead = binaryStream.Read(buffer, 0, buffer.Length)) != 0) { retryCount = 0; //get the request object for the actual chunk while (retryCount < REQUEST_RETRY_COUNT) { Stream requestStream = null; HttpWebRequest chunkRequest; try { chunkRequest = CreateChunkUploadWebRequest(requestData.ToString(), server, uploadData, boundary, out requestStream); SnTrace.Category(ClientContext.TraceCategory).Write("###>REQ: {0}", chunkRequest.RequestUri); if (uploadData.UseChunk) { chunkRequest.Headers.Set("Content-Range", string.Format("bytes {0}-{1}/{2}", start, start + bytesRead - 1, binaryStream.Length)); } //write the chunk into the request stream requestStream.Write(buffer, 0, bytesRead); requestStream.Write(trailer, 0, trailer.Length); await requestStream.FlushAsync(); } finally { if (requestStream != null) { requestStream.Close(); } } //send the request try { using (var wr = await chunkRequest.GetResponseAsync()) { var rs = await ReadResponseStringAsync(wr); uploadedContent = JsonHelper.Deserialize(rs); } // successful request: skip out from the retry loop break; } catch (WebException ex) { if (retryCount >= REQUEST_RETRY_COUNT - 1) { var ce = new ClientException("Error during binary upload.", ex); ce.Data["SiteUrl"] = requestData.SiteUrl; ce.Data["Parent"] = requestData.ContentId != 0 ? requestData.ContentId.ToString() : requestData.Path; ce.Data["FileName"] = uploadData.FileName; ce.Data["ContentType"] = uploadData.ContentType; throw ce; } else { Thread.Sleep(50); } } retryCount++; } start += bytesRead; // notify the caller about every chunk that was uploaded successfully if (progressCallback != null) { progressCallback(start); } } if (uploadedContent == null) { return(null); } int contentId = uploadedContent.Id; var content = Content.Create(contentId); content.Name = uploadedContent.Name; content.Path = uploadedContent.Url; return(content); }
private static async Task <Content> UploadInternalAsync(Stream binaryStream, UploadData uploadData, ODataRequest requestData, ServerContext server = null, Action <int> progressCallback = null) { // force set values uploadData.UseChunk = binaryStream.Length > ClientContext.Current.ChunkSizeInBytes; if (uploadData.FileLength == 0) { uploadData.FileLength = binaryStream.Length; } requestData.Parameters.Add("create", "1"); dynamic uploadedContent = null; // Get ChunkToken try { SnTrace.Category(ClientContext.TraceCategory).Write("###>REQ: {0}", requestData); var httpContent = new StringContent(uploadData.ToString()); httpContent.Headers.ContentType = new MediaTypeHeaderValue(JsonContentMimeType); await ProcessWebResponseAsync(requestData.ToString(), HttpMethod.Post, server, httpContent, async response => { uploadData.ChunkToken = await response.Content.ReadAsStringAsync().ConfigureAwait(false); }, CancellationToken.None).ConfigureAwait(false); } catch (WebException ex) { var ce = new ClientException("Error during binary upload.", ex); ce.Data["SiteUrl"] = requestData.SiteUrl; ce.Data["Parent"] = requestData.ContentId != 0 ? requestData.ContentId.ToString() : requestData.Path; ce.Data["FileName"] = uploadData.FileName; ce.Data["ContentType"] = uploadData.ContentType; throw ce; } // Reuse previous request data, but remove unnecessary parameters requestData.Parameters.Remove("create"); // Send subsequent requests var boundary = "---------------------------" + DateTime.UtcNow.Ticks.ToString("x"); var uploadFormData = uploadData.ToKeyValuePairs(); var contentDispositionHeaderValue = new ContentDispositionHeaderValue("attachment") { FileName = uploadData.FileName }; var buffer = new byte[ClientContext.Current.ChunkSizeInBytes]; int bytesRead; var start = 0; while ((bytesRead = binaryStream.Read(buffer, 0, buffer.Length)) != 0) { // Prepare the current chunk request var httpContent = new MultipartFormDataContent(boundary); foreach (var item in uploadFormData) { httpContent.Add(new StringContent(item.Value), item.Key); } httpContent.Headers.ContentDisposition = contentDispositionHeaderValue; if (uploadData.UseChunk) { httpContent.Headers.ContentRange = new ContentRangeHeaderValue(start, start + bytesRead - 1, binaryStream.Length); } // Add the chunk as a stream into the request content var postedStream = new MemoryStream(buffer, 0, bytesRead); httpContent.Add(new StreamContent(postedStream), "files[]", uploadData.FileName); // Process await ProcessWebResponseAsync(requestData.ToString(), HttpMethod.Post, server, httpContent, async response => { var rs = await response.Content.ReadAsStringAsync().ConfigureAwait(false); uploadedContent = JsonHelper.Deserialize(rs); }, CancellationToken.None).ConfigureAwait(false); start += bytesRead; // Notify the caller about every chunk that was uploaded successfully progressCallback?.Invoke(start); } if (uploadedContent == null) { return(null); } int contentId = uploadedContent.Id; var content = Content.Create(contentId); content.Name = uploadedContent.Name; content.Path = uploadedContent.Url; return(content); }