private void setMetadata(UploadChunkState asyncState)
        {
            this.m_IsDone = true;
            var _asyncOperation = asyncState.m_AsyncOp;
            var _request = default(WebRequest);

            try
            {
                _request = asyncState.m_Request = this.getWebRequest(Properties.Settings.Default.HTTP_PUT, "metadata");
                _request.Headers[MsVersionHeader] = HeaderVersion;

                var _meta = asyncState.m_Metadata.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                foreach (var item in _meta)
                {
                    var _kvp = item.Split("=".ToCharArray());
                    var _k = _kvp[0];
                    var _v = _kvp[1];
                    if (_k.StartsWith("x-ms-meta-"))
                        _request.Headers[_k] = _v;
                }

                _request.BeginGetResponse(this.setMetadataResponse, asyncState);
            }
            catch (Exception exception)
            {
                if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException))
                    throw;

                this.uploadFileCompleted(asyncState, string.Empty, false, null);
            }
        }
        private void uploadFileCompleted(UploadChunkState asyncState, string result, bool cancelled, Exception exception)
        {
            asyncState.Close();

            var _eventArgs = new UploadFileCompletedEventArgs(result, exception, cancelled, this.m_AsyncOperation.UserSuppliedState);
            this.InvokeOperationCompeted(this.m_AsyncOperation, this.m_UploadOperationCompleted, _eventArgs);
        }
        private void sendCancel(UploadChunkState asyncState)
        {
            this.EndTimestamp = DateTime.Now;

            // Nothing to cancel, so we just end.
            this.uploadFileCompleted(asyncState, string.Empty, this.m_IsCancelled, asyncState.m_Exception);
        }
        private void sendComplete(UploadChunkState asyncState)
        {
            this.m_IsDone = true;
            var _asyncOperation = asyncState.m_AsyncOp;
            var _request = default(WebRequest);

            try
            {
                this.EndTimestamp = DateTime.Now;
                _request = asyncState.m_Request = this.getWebRequest(Properties.Settings.Default.HTTP_PUT, "blocklist");
                _request.Headers[MsVersionHeader] = HeaderVersion;
                _request.BeginGetRequestStream(this.sendCompleteRequest, asyncState);
            }
            catch (Exception exception)
            {
                if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException))
                    throw;

                if (null != _request)
                    _request.Abort();

                asyncState.m_Exception = exception;

                this.sendCancel(asyncState);
            }
        }
        private static void appendChunkRetry(UploadChunkState asyncState)
        {
            Console.WriteLine("Retry: " + asyncState.m_Progress.LastBytesSent);

            asyncState.m_Progress.BytesSent -= asyncState.m_Progress.LastBytesSent;
            asyncState.m_AzureClient.appendChunk(asyncState);
        }
        private void appendChunkReadCallback(string response, UploadChunkState asyncState)
        {
            var _ex = default(Exception);
            this.processException(ref _ex, asyncState.m_Exception);

            if (_ex != null)
            {
                asyncState.m_Exception = _ex;
                this.sendCancel(asyncState);
            }
            else if (response == ServerResponses.AppendFileRetry.ToString())
            {
                if (this.m_IsCancelled)
                {
                    asyncState.m_Exception = _ex;
                    this.sendCancel(asyncState);
                }
                else
                {
                    appendChunkRetry(asyncState);
                }
            }
            else if (this.m_ProgressData.BytesSent != this.m_ProgressData.TotalBytesToSend)
            {
                if (this.m_IsCancelled)
                {
                    asyncState.m_Exception = _ex;
                    this.sendCancel(asyncState);
                }
                else
                {
                    this.appendChunk(asyncState);
                }
            }
            else
            {
                this.m_IsDone = true;
                this.sendComplete(asyncState);
            }
        }
        private void appendChunkWriteCallback(UploadChunkState asyncState)
        {
            var _ex = default(Exception);
            this.processException(ref _ex, asyncState.m_Exception);

            if (_ex != null)
            {
                asyncState.m_Exception = _ex;
                this.sendCancel(asyncState);
            }
            else
            {
                try
                {
                    m_WebRequest.BeginGetResponse(appendChunkGetResponse, asyncState);
                }
                catch (Exception ex2)
                {
                    this.processException(ref _ex, ex2);
                    asyncState.m_Exception = _ex;
                    this.sendCancel(asyncState);
                }
            }
        }
        private void appendChunk(UploadChunkState asyncState)
        {
            var _asyncOperation = asyncState.m_AsyncOp;

            try
            {
                if (this.m_IsCancelled)
                {
                    this.sendCancel(asyncState);
                    return;
                }

                var _blockId = asyncState.GetNextBlockId();
                var _len = asyncState.FillBuffer();
                var _request = asyncState.m_Request = this.getWebRequest(Properties.Settings.Default.HTTP_PUT, _blockId);

                _request.BeginGetRequestStream(UploadClientAzure.uploadChunkRequestCallback, asyncState);
            }
            catch (Exception exception)
            {
                if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException))
                    throw;

                if (!(exception is WebException) && !(exception is SecurityException))
                    exception = new WebException(Properties.Settings.Default.UnknownError, exception);

                asyncState.m_Exception = exception;

                this.sendCancel(asyncState);
            }
        }
        /// <summary>
        /// Begins uploading the content.
        /// </summary>
        /// <param name="content">The stream to upload.</param>
        /// <param name="fileName">The name of the file the stream is being uploaded to.</param>
        /// <param name="metadata">Optional metadata string containing additional information to send with the file.</param>
        /// <param name="autoCloseStream">True to close the provided content stream once the upload completes; otherwise false to leave open.</param>
        /// <param name="userToken">Optional user state associated with this request.</param>
        public void UploadStreamAsync(Stream content, string fileName, string metadata, bool autoCloseStream, object userToken = null)
        {
            if (null == content)
                throw new ArgumentNullException("content");

            if (!content.CanRead)
                throw new ArgumentException("The provided content Stream is not readable.", "content");

            if (!content.CanSeek)
                throw new ArgumentException("The provided content Stream is not seekable.", "content");

            if (content.Length < 1)
                throw new ArgumentException("Content length is zero (0); nothing to send.", "content");

            if (content.Length == content.Position)
                throw new ArgumentException("Content position is at the end of the file; no bytes left to send.", "content");

            if (string.IsNullOrWhiteSpace(fileName))
                throw new ArgumentNullException("fileName");

            this.initUploadClientState();
            this.clearUploadClientState();

            this.FileName = Path.GetFileName(fileName);
            this.ContentLength = content.Length;

            // Azure Uri
            var _uriBuilder = new UriBuilder(m_ResolvedUri);
            _uriBuilder.Path += string.Format(CultureInfo.InvariantCulture, "/{0}", this.FileName);
            this.m_ResolvedUri = _uriBuilder.Uri;

            this.m_AsyncOperation = AsyncOperationManager.CreateOperation(userToken);

            try
            {
                if (!string.IsNullOrEmpty(metadata))
                    metadata = HttpUtility.HtmlEncode(metadata);

                var _request = this.getWebRequest(Properties.Settings.Default.HTTP_HEAD, "metadata");
                _request.Headers[MsVersionHeader] = HeaderVersion;
                _request.Headers[ContentMD5] = Convert.ToBase64String(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(content));

                var _asyncState = new UploadChunkState(_request, content, fileName, metadata, autoCloseStream, this.appendChunkWriteCallback, this.appendChunkReadCallback, this.m_AsyncOperation, this.m_ProgressData, this);
                _request.BeginGetResponse(this.sendFileCheckResponse, _asyncState);
            }
            catch (Exception exception)
            {
                if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException))
                {
                    throw;
                }

                this.processException(ref exception, exception);
                if (null != content)
                    content.Close();

                var _eventArgs = new UploadFileCompletedEventArgs(null, exception, this.m_IsCancelled, this.m_AsyncOperation.UserSuppliedState);
                this.InvokeOperationCompeted(this.m_AsyncOperation, this.m_UploadOperationCompleted, _eventArgs);
            }
        }