Beispiel #1
0
        /// <summary>
        /// Get the status of the session. Stores returned session internally.
        /// Updates internal list of ranges remaining to be uploaded (according to the server).
        /// </summary>
        /// <returns>UploadSession returned by the server.</returns>
        public virtual async Task <UploadSession> UpdateSessionStatusAsync()
        {
            var request    = new UploadSessionRequest(this.Session, this.client, null);
            var newSession = await request.GetAsync().ConfigureAwait(false);

            var newRangesRemaining = this.GetRangesRemaining(newSession);

            this.rangesRemaining = newRangesRemaining;
            newSession.UploadUrl = this.Session.UploadUrl; // Sometimes the UploadUrl is not returned
            this.Session         = newSession;
            return(newSession);
        }
        // Uploads a large file to the current user's root directory.
        private static void UploadLargeFile(GraphServiceClient graphClient, Stream fileStream, string fileName)
        {
            // Create the upload session. The access token is no longer required as you have session established for the upload.
            // POST /v1.0/drive/root:/UploadLargeFile.bmp:/microsoft.graph.createUploadSession
            Microsoft.Graph.UploadSession uploadSession = graphClient.Me.Drive.Root.ItemWithPath(fileName).CreateUploadSession().Request().PostAsync().Result;

            int maxChunkSize = 320 * 1024; // 320 KB - Change this to your chunk size. 5MB is the default.
            ChunkedUploadProvider provider = new ChunkedUploadProvider(uploadSession, graphClient, fileStream, maxChunkSize);

            //Replace own implementation in favour of UploadAsync-Helper (https://github.com/OneDrive/onedrive-sdk-csharp/blob/master/docs/chunked-uploads.md)
            _ = provider.UploadAsync().Result;
        }
Beispiel #3
0
        internal List <Tuple <long, long> > GetRangesRemaining(UploadSession session)
        {
            // nextExpectedRanges: https://dev.onedrive.com/items/upload_large_files.htm
            // Sample: ["12345-55232","77829-99375"]
            // Also, second number in range can be blank, which means 'until the end'
            var newRangesRemaining = new List <Tuple <long, long> >();

            foreach (var range in session.NextExpectedRanges)
            {
                var rangeSpecifiers = range.Split('-');
                newRangesRemaining.Add(new Tuple <long, long>(long.Parse(rangeSpecifiers[0]),
                                                              string.IsNullOrEmpty(rangeSpecifiers[1]) ? this.totalUploadLength - 1 : long.Parse(rangeSpecifiers[1])));
            }

            return(newRangesRemaining);
        }
Beispiel #4
0
        /// <summary>
        /// Helps with resumable uploads. Generates chunk requests based on <paramref name="session"/>
        /// information, and can control uploading of requests using <paramref name="client"/>
        /// </summary>
        /// <param name="session">Session information.</param>
        /// <param name="client">Client used to upload chunks.</param>
        /// <param name="uploadStream">Readable, seekable stream to be uploaded. Length of session is determined via uploadStream.Length</param>
        /// <param name="maxChunkSize">Max size of each chunk to be uploaded. Multiple of 320 KiB (320 * 1024) is required.
        /// If less than 0, default value of 5 MiB is used. .</param>
        public ChunkedUploadProvider(UploadSession session, IBaseClient client, Stream uploadStream, int maxChunkSize = -1)
        {
            if (!uploadStream.CanRead || !uploadStream.CanSeek)
            {
                throw new ArgumentException("Must provide stream that can read and seek");
            }

            this.Session         = session;
            this.client          = client;
            this.uploadStream    = uploadStream;
            this.rangesRemaining = this.GetRangesRemaining(session);
            this.maxChunkSize    = maxChunkSize < 0 ? DefaultMaxChunkSize : maxChunkSize;
            if (this.maxChunkSize % RequiredChunkSizeIncrement != 0)
            {
                throw new ArgumentException("Max chunk size must be a multiple of 320 KiB", nameof(maxChunkSize));
            }
        }
        /// <summary>
        /// Process raw HTTP response from Upload request
        /// </summary>
        /// <typeparam name="T">The type to return</typeparam>
        /// <param name="response">The HttpResponseMessage to handle.</param>
        /// <returns></returns>
        public async Task <UploadResult <T> > HandleResponse <T>(HttpResponseMessage response)
        {
            if (response.Content == null)
            {
                throw new ServiceException(new Error
                {
                    Code    = ErrorConstants.Codes.GeneralException,
                    Message = ErrorConstants.Messages.NoResponseForUpload
                });
            }

            // Give back the info from the server for ongoing upload as the upload is ongoing
            using (Stream responseSteam = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
            {
                try
                {
                    if (!response.IsSuccessStatusCode)
                    {
                        ErrorResponse errorResponse   = this._serializer.DeserializeObject <ErrorResponse>(responseSteam);
                        Error         error           = errorResponse.Error;
                        string        rawResponseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                        // Throw exception to know something went wrong.
                        throw new ServiceException(error, response.Headers, response.StatusCode, rawResponseBody);
                    }

                    var uploadResult = new UploadResult <T>();

                    /*
                     * Check if we have a status code 201 to know if the upload completed successfully.
                     * This will be returned when uploading a FileAttachment with a location header but empty response hence
                     * This could also be returned when uploading a DriveItem with  an ItemResponse but no location header.
                     */
                    if (response.StatusCode == HttpStatusCode.Created)
                    {
                        uploadResult.ItemResponse = this._serializer.DeserializeObject <T>(responseSteam);
                        uploadResult.Location     = response.Headers.Location;
                    }
                    else
                    {
                        /*
                         * The response could be either a 200 or a 202 response.
                         * DriveItem Upload returns the upload session in a 202 response while FileAttachment in a 200 response
                         * However, successful upload completion for a DriveItem the response could also come in a 200 response and
                         * hence we validate this by checking the NextExpectedRanges parameter which is present in an ongoing upload
                         */
                        UploadSession uploadSession = this._serializer.DeserializeObject <UploadSession>(responseSteam);
                        if (uploadSession?.NextExpectedRanges != null)
                        {
                            uploadResult.UploadSession = uploadSession;
                        }
                        else
                        {
                            //Upload is most likely done as DriveItem info may come in a 200 response
                            responseSteam.Position    = 0; //reset
                            uploadResult.ItemResponse = this._serializer.DeserializeObject <T>(responseSteam);
                        }
                    }

                    return(uploadResult);
                }
                catch (JsonSerializationException exception)
                {
                    string rawResponseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                    throw new ServiceException(new Error()
                    {
                        Code    = ErrorConstants.Codes.GeneralException,
                        Message = ErrorConstants.Messages.UnableToDeserializeContent,
                    },
                                               response.Headers,
                                               response.StatusCode,
                                               rawResponseBody,
                                               exception);
                }
            }
        }
 public UploadSessionRequest(UploadSession session, IBaseClient client, IEnumerable <Option> options)
     : base(session.UploadUrl, client, options)
 {
     this.session = session;
 }