//============================================================================= Upload API

        /// <summary>
        /// Uploads a file to the server into the provided container.
        /// </summary>
        /// <param name="binaryStream">File contents.</param>
        /// <param name="uploadData">Upload parameters.</param>
        /// <param name="parentId">Parent id.</param>
        /// <param name="server">Target server.</param>
        /// <param name="progressCallback">An optional callback method that is called after each chunk is uploaded to the server.</param>
        /// <returns>The uploaded file content returned at the end of the upload request.</returns>
        public static async Task <Content> UploadAsync(Stream binaryStream, UploadData uploadData, int parentId, ServerContext server = null, Action <int> progressCallback = null)
        {
            var requestData = new ODataRequest(server)
            {
                ActionName = "Upload",
                ContentId  = parentId
            };

            return(await UploadInternalAsync(binaryStream, uploadData, requestData, server, progressCallback).ConfigureAwait(false));
        }
        /// <summary>
        /// Uploads a file to the server into the provided container.
        /// </summary>
        /// <param name="binaryStream">File contents.</param>
        /// <param name="uploadData">Upload parameters.</param>
        /// <param name="parentPath">Parent path.</param>
        /// <param name="server">Target server.</param>
        /// <param name="progressCallback">An optional callback method that is called after each chunk is uploaded to the server.</param>
        /// <returns>The uploaded file content returned at the end of the upload request.</returns>
        public static async Task <Content> UploadAsync(Stream binaryStream, UploadData uploadData, string parentPath, ServerContext server = null, Action <int> progressCallback = null)
        {
            var requestData = new ODataRequest()
            {
                SiteUrl    = ServerContext.GetUrl(server),
                ActionName = "Upload",
                Path       = parentPath
            };

            return(await UploadInternalAsync(binaryStream, uploadData, requestData, server, progressCallback));
        }
Beispiel #3
0
        /// <summary>
        /// Uploads a file to the server into the provided container.
        /// </summary>
        /// <param name="text">File contents.</param>
        /// <param name="uploadData">Upload parameters.</param>
        /// <param name="parentPath">Parent path.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <param name="server">Target server.</param>
        /// <returns>The uploaded file content returned at the end of the upload request.</returns>
        public static async Task <Content> UploadTextAsync(string text, UploadData uploadData, string parentPath,
                                                           CancellationToken cancellationToken, ServerContext server = null)
        {
            var requestData = new ODataRequest(server)
            {
                ActionName = "Upload",
                Path       = parentPath
            };

            return(await UploadTextInternalAsync(text, uploadData, requestData, cancellationToken, server).ConfigureAwait(false));
        }
        private static async Task <Content> UploadInternalAsync(Stream binaryStream, UploadData uploadData, ODataRequest requestData, ServerContext server = null, Action <int> progressCallback = null)
        {
            server ??= ClientContext.Current.Server;

            // 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 retryCount = 0;

                await Retrier.RetryAsync(10, 1000, async() =>
                {
                    retryCount++;
                    var retryText = retryCount > 1 ? $" (retry {retryCount})" : string.Empty;
                    server.Logger?.LogTrace($"Uploading initial data of {uploadData.FileName}{retryText}.");

                    var httpContent = new StringContent(uploadData.ToString());
                    httpContent.Headers.ContentType = new MediaTypeHeaderValue(JsonContentMimeType);
                    await ProcessWebResponseAsync(requestData.ToString(), HttpMethod.Post, server, httpContent,
                                                  response =>
                    {
                        uploadData.ChunkToken = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
                    }, CancellationToken.None).ConfigureAwait(false);
                }, (i, exception) =>
                {
                    // choose the exceptions when we can retry the operation
                    return(exception switch
                    {
                        null => true,
                        ClientException cex when
                            (int) cex.StatusCode == 429 ||
                        cex.ErrorData?.ExceptionType == "NodeIsOutOfDateException"
                        => false,
                        _ => throw exception
                    });
                });
Beispiel #5
0
        private static async Task <Content> UploadTextInternalAsync(string text, UploadData uploadData, ODataRequest requestData,
                                                                    CancellationToken cancellationToken, ServerContext server = null)
        {
            // force set values
            if (text.Length > ClientContext.Current.ChunkSizeInBytes)
            {
                throw new InvalidOperationException($"Cannot upload a text that longer than the chunk size " +
                                                    $"({ClientContext.Current.ChunkSizeInBytes}).");
            }
            if (uploadData.FileLength == 0)
            {
                uploadData.FileLength = text.Length;
            }
            uploadData.FileText = text;

            dynamic uploadedContent = null;

            var model       = JsonHelper.GetJsonPostModel(uploadData.ToDictionary());
            var httpContent = new StringContent(model);

            httpContent.Headers.ContentType = new MediaTypeHeaderValue(JsonContentMimeType);

            await ProcessWebResponseAsync(requestData.ToString(), HttpMethod.Post, server, httpContent,
                                          async response =>
            {
                if (response != null)
                {
                    var rs          = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                    uploadedContent = JsonHelper.Deserialize(rs);
                }
            }, cancellationToken).ConfigureAwait(false);

            if (uploadedContent == null)
            {
                return(null);
            }

            int contentId = uploadedContent.Id;
            var content   = Content.Create(contentId);

            content.Name = uploadedContent.Name;
            content.Path = uploadedContent.Url;

            return(content);
        }
Beispiel #6
0
        /// <summary>
        /// Uploads a file to the server into the provided container.
        /// </summary>
        /// <param name="parentId">Parent id.</param>
        /// <param name="fileName">Name of the file to upload.</param>
        /// <param name="stream">File contents.</param>
        /// <param name="contentType">Content type of the file. Default is determined by the container.</param>
        /// <param name="propertyName">Name of the field to upload to. Default is Binary.</param>
        /// <param name="server">Target server.</param>
        /// <param name="progressCallback">An optional callback method that is called after each chunk is uploaded to the server.</param>
        /// <returns>The uploaded file content returned at the end of the upload request.</returns>
        public static async Task <Content> UploadAsync(int parentId, string fileName, Stream stream, string contentType = null, string propertyName = null, ServerContext server = null, Action <int> progressCallback = null)
        {
            var uploadData = new UploadData()
            {
                FileName   = fileName,
                FileLength = stream.Length
            };

            if (!string.IsNullOrEmpty(contentType))
            {
                uploadData.ContentType = contentType;
            }

            if (!string.IsNullOrEmpty(propertyName))
            {
                uploadData.PropertyName = propertyName;
            }

            return(await RESTCaller.UploadAsync(stream, uploadData, parentId, server, progressCallback));
        }
Beispiel #7
0
        /// <summary>
        /// Uploads a file to the server into the provided container.
        /// </summary>
        /// <param name="parentId">Parent id.</param>
        /// <param name="fileName">Name of the file to upload.</param>
        /// <param name="fileText">File content.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <param name="contentType">Content type of the file.</param>
        /// <param name="propertyName">Name of the field to upload to. Default is Binary.</param>
        /// <param name="server">Target server.</param>
        /// <returns>The uploaded file content returned at the end of the upload request.</returns>
        public static async Task <Content> UploadTextAsync(int parentId, string fileName, string fileText,
                                                           CancellationToken cancellationToken,
                                                           string contentType = null, string propertyName = null, ServerContext server = null)
        {
            var uploadData = new UploadData()
            {
                FileName    = fileName,
                ContentType = contentType,
            };

            if (!string.IsNullOrEmpty(contentType))
            {
                uploadData.ContentType = contentType;
            }

            if (!string.IsNullOrEmpty(propertyName))
            {
                uploadData.PropertyName = propertyName;
            }

            return(await RESTCaller.UploadTextAsync(fileText, uploadData, parentId, cancellationToken, server)
                   .ConfigureAwait(false));
        }
        private static HttpWebRequest CreateChunkUploadWebRequest(string url, ServerContext server, UploadData uploadData, string boundary, out Stream requestStream)
        {
            var myRequest = GetRequest(url, server);

            myRequest.Method      = "POST";
            myRequest.ContentType = "multipart/form-data; boundary=" + boundary;

            myRequest.Headers.Add("Content-Disposition", "attachment; filename=\"" + Uri.EscapeUriString(uploadData.FileName) + "\"");

            var boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

            // we must not close the stream after this as we need to write the chunk into it in the caller method
            requestStream = myRequest.GetRequestStream();

            //write form data values
            foreach (var kvp in uploadData.ToDictionary())
            {
                requestStream.Write(boundarybytes, 0, boundarybytes.Length);

                var formitem      = string.Format(UPLOAD_FORMDATA_TEMPLATE, kvp.Key, kvp.Value);
                var formitembytes = Encoding.UTF8.GetBytes(formitem);

                requestStream.Write(formitembytes, 0, formitembytes.Length);
            }

            //write a boundary
            requestStream.Write(boundarybytes, 0, boundarybytes.Length);

            //write file name and content type
            var header      = string.Format(UPLOAD_HEADER_TEMPLATE, "files[]", Uri.EscapeUriString(uploadData.FileName));
            var headerbytes = Encoding.UTF8.GetBytes(header);

            requestStream.Write(headerbytes, 0, headerbytes.Length);

            return(myRequest);
        }
        private static WebRequest CreateInitUploadWebRequest(string url, ServerContext server, UploadData uploadData)
        {
            var myRequest = GetRequest(url, server);

            myRequest.Method = "POST";

            var postDataBytes = Encoding.ASCII.GetBytes(uploadData.ToString());

            myRequest.ContentLength = postDataBytes.Length;
            myRequest.ContentType   = UPLOAD_CONTENTTYPE;

            using (var reqStream = myRequest.GetRequestStream())
            {
                reqStream.Write(postDataBytes, 0, postDataBytes.Length);
            }

            return(myRequest);
        }
Beispiel #10
0
        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);
        }
Beispiel #11
0
        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);
        }