public ICancellableAsyncResult BeginOpenRead(AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state)
        {
            StorageAsyncResult<Stream> storageAsyncResult = new StorageAsyncResult<Stream>(callback, state);

            ICancellableAsyncResult result = this.BeginFetchAttributes(
                accessCondition,
                options,
                operationContext,
                ar =>
                {
                    try
                    {
                        this.EndFetchAttributes(ar);
                        storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);
                        AccessCondition streamAccessCondition = AccessCondition.CloneConditionWithETag(accessCondition, this.Properties.ETag);
                        BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, this.BlobType, this.ServiceClient, false);
                        storageAsyncResult.Result = new BlobReadStream(this, streamAccessCondition, modifiedOptions, operationContext);
                        storageAsyncResult.OnComplete();
                    }
                    catch (Exception e)
                    {
                        storageAsyncResult.OnComplete(e);
                    }
                },
                null /* state */);

            storageAsyncResult.CancelDelegate = result.Cancel;
            return storageAsyncResult;
        }
예제 #2
0
        /// <summary>
        /// Dispatches a write operation.
        /// </summary>
        /// <param name="asyncResult">The reference to the pending asynchronous request to finish.</param>
        private void DispatchWrite(StorageAsyncResult <NullType> asyncResult)
        {
            if (this.internalBuffer.Length == 0)
            {
                if (asyncResult != null)
                {
                    asyncResult.OnComplete(this.lastException);
                }

                return;
            }

            MultiBufferMemoryStream bufferToUpload = this.internalBuffer;

            this.internalBuffer = new MultiBufferMemoryStream(this.Blob.ServiceClient.BufferManager);
            bufferToUpload.Seek(0, SeekOrigin.Begin);

            string bufferMD5 = null;

            if (this.blockMD5 != null)
            {
                bufferMD5 = this.blockMD5.ComputeHash();
                this.blockMD5.Dispose();
                this.blockMD5 = new MD5Wrapper();
            }

            if (this.blockBlob != null)
            {
                string blockId = this.GetCurrentBlockId();
                this.blockList.Add(blockId);
                this.WriteBlock(bufferToUpload, blockId, bufferMD5, asyncResult);
            }
            else
            {
                if ((bufferToUpload.Length % Constants.PageSize) != 0)
                {
                    this.lastException = new IOException(SR.InvalidPageSize);
                    throw this.lastException;
                }

                long offset = this.currentPageOffset;
                this.currentPageOffset += bufferToUpload.Length;
                this.WritePages(bufferToUpload, offset, bufferMD5, asyncResult);
            }
        }
예제 #3
0
        /// <summary>
        /// Starts an asynchronous AppendBlock operation as soon as the parallel
        /// operation semaphore becomes available. Since parallelism is always set
        /// to 1 for append blobs, appendblock operations are called serially.
        /// </summary>
        /// <param name="blockData">Data to be uploaded.</param>
        /// <param name="offset">Offset within the append blob to be used to set the append offset conditional header.</param>
        /// <param name="blockMD5">MD5 hash of the data to be uploaded.</param>
        /// <param name="asyncResult">The reference to the pending asynchronous request to finish.</param>
        private void WriteAppendBlock(Stream blockData, long offset, string blockMD5, StorageAsyncResult <NullType> asyncResult)
        {
            this.noPendingWritesEvent.Increment();
            this.parallelOperationSemaphore.WaitAsync(calledSynchronously =>
            {
                try
                {
                    this.accessCondition.IfAppendPositionEqual = offset;

                    int previousResultsCount       = this.operationContext.RequestResults.Count;
                    ICancellableAsyncResult result = this.appendBlob.BeginAppendBlock(
                        blockData,
                        blockMD5,
                        this.accessCondition,
                        this.options,
                        this.operationContext,
                        this.AppendBlockCallback,
                        previousResultsCount /* state */);

                    if (asyncResult != null)
                    {
                        // We do not need to do this inside a lock, as asyncResult is
                        // not returned to the user yet.
                        asyncResult.CancelDelegate = result.Cancel;
                    }
                }
                catch (Exception e)
                {
                    this.lastException = e;
                    this.noPendingWritesEvent.Decrement();
                    this.parallelOperationSemaphore.Release();
                }
                finally
                {
                    if (asyncResult != null)
                    {
                        asyncResult.UpdateCompletedSynchronously(calledSynchronously);
                        asyncResult.OnComplete(this.lastException);
                    }
                }
            });
        }
        private void WriteStreamCallback(IAsyncResult ar)
        {
            StorageAsyncResult <NullType> storageAsyncResult = (StorageAsyncResult <NullType>)ar.AsyncState;

            storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);

            Exception endException = null;

            try
            {
                this.wrappedStream.EndWrite(ar);
                this.position += (int)storageAsyncResult.OperationState;
            }
            catch (Exception e)
            {
                endException = e;
            }

            storageAsyncResult.OnComplete(endException);
        }
        private void WriteRange(Stream rangeData, long offset, string contentMD5, StorageAsyncResult <NullType> asyncResult)
        {
            this.noPendingWritesEvent.Increment();

            this.parallelOperationSemaphore.WaitAsync(calledSynchronously =>
            {
                try
                {
                    ICancellableAsyncResult result = this.file.BeginWriteRange(
                        rangeData,
                        offset,
                        contentMD5,
                        this.accessCondition,
                        this.options,
                        this.operationContext,
                        this.WriteRangeCallback,
                        null /* state */);

                    if (asyncResult != null)
                    {
                        // We do not need to do this inside a lock, as asyncResult is
                        // not returned to the user yet.
                        asyncResult.CancelDelegate = result.Cancel;
                    }
                }
                catch (Exception e)
                {
                    this.lastException = e;
                    this.noPendingWritesEvent.Decrement();
                    this.parallelOperationSemaphore.Release();
                }
                finally
                {
                    if (asyncResult != null)
                    {
                        asyncResult.UpdateCompletedSynchronously(calledSynchronously);
                        asyncResult.OnComplete(this.lastException);
                    }
                }
            });
        }
예제 #6
0
        private void DownloadRangeToStreamCallback(IAsyncResult ar)
        {
            StorageAsyncResult <int> storageAsyncResult = (StorageAsyncResult <int>)ar.AsyncState;

            storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);

            try
            {
                this.blob.EndDownloadRangeToStream(ar);

                ArraySegment <byte> bufferSegment = (ArraySegment <byte>)storageAsyncResult.OperationState;
                this.internalBuffer.Seek(0, SeekOrigin.Begin);
                storageAsyncResult.Result = this.ConsumeBuffer(bufferSegment.Array, bufferSegment.Offset, bufferSegment.Count);
            }
            catch (Exception e)
            {
                this.lastException = e;
            }

            storageAsyncResult.OnComplete(this.lastException);
        }
예제 #7
0
        private void WriteBlock(Stream blockData, string blockId, string blockMD5, StorageAsyncResult <NullType> asyncResult)
        {
            this.noPendingWritesEvent.Increment();
            this.parallelOperationSemaphore.WaitAsync(calledSynchronously =>
            {
                try
                {
                    ICancellableAsyncResult result = this.blockBlob.BeginPutBlock(
                        blockId,
                        blockData,
                        blockMD5,
                        this.accessCondition,
                        this.options,
                        this.operationContext,
                        this.PutBlockCallback,
                        null /* state */);

                    if (asyncResult != null)
                    {
                        // We do not need to do this inside a lock, as asyncResult is
                        // not returned to the user yet.
                        asyncResult.CancelDelegate = result.Cancel;
                    }
                }
                catch (Exception e)
                {
                    this.lastException = e;
                }
                finally
                {
                    if (asyncResult != null)
                    {
                        asyncResult.UpdateCompletedSynchronously(calledSynchronously);
                        asyncResult.OnComplete(this.lastException);
                    }
                }
            });
        }
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            // Keep buffering until we have 16 bytes of IV.
            if (this.bufferIV && this.position < 16)
            {
                int bytesToCopy = 16 - (int)this.position;
                bytesToCopy = count > bytesToCopy ? bytesToCopy : count;
                Array.Copy(buffer, offset, this.iv, (int)this.position, bytesToCopy);
                this.position += bytesToCopy;
                offset        += bytesToCopy;
                count         -= bytesToCopy;
            }

            // Wrap user stream with LengthLimitingStream. This stream will be used to discard the extra bytes we downloaded in order to deal with AES block size.
            // Create crypto stream around the length limiting stream once per download and start writing to it. During retries, the state is maintained and
            // new crypto streams will not be created each time.
            if (this.cryptoStream == null)
            {
                LengthLimitingStream lengthLimitingStream = new LengthLimitingStream(this.userStream, this.discardFirst, this.userProvidedLength);
                this.cryptoStream = this.encryptionPolicy.DecryptBlob(lengthLimitingStream, this.metadata, out this.transform, this.requireEncryption, iv: !this.bufferIV ? null : this.iv, noPadding: this.noPadding);
            }

            StorageAsyncResult <NullType> storageAsyncResult = new StorageAsyncResult <NullType>(callback, state);

            if (count <= 0)
            {
                storageAsyncResult.OnComplete();
            }
            else
            {
                // Route the remaining data through the crypto stream.
                storageAsyncResult.OperationState = count;
                this.cryptoStream.BeginWrite(buffer, offset, count, this.WriteStreamCallback, storageAsyncResult);
            }

            return(storageAsyncResult);
        }
        private void DeleteIfExistsHandler(DeleteSnapshotsOption deleteSnapshotsOption, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, StorageAsyncResult<bool> storageAsyncResult)
        {
            lock (storageAsyncResult.CancellationLockerObject)
            {
                ICancellableAsyncResult savedExistsResult = this.BeginExists(
                    options,
                    operationContext,
                    existsResult =>
                    {
                        storageAsyncResult.UpdateCompletedSynchronously(existsResult.CompletedSynchronously);
                        lock (storageAsyncResult.CancellationLockerObject)
                        {
                            storageAsyncResult.CancelDelegate = null;
                            try
                            {
                                bool exists = this.EndExists(existsResult);
                                if (!exists)
                                {
                                    storageAsyncResult.Result = false;
                                    storageAsyncResult.OnComplete();
                                    return;
                                }

                                ICancellableAsyncResult savedDeleteResult = this.BeginDelete(
                                    deleteSnapshotsOption,
                                    accessCondition,
                                    options,
                                    operationContext,
                                    deleteResult =>
                                    {
                                        storageAsyncResult.UpdateCompletedSynchronously(deleteResult.CompletedSynchronously);
                                        storageAsyncResult.CancelDelegate = null;
                                        try
                                        {
                                            this.EndDelete(deleteResult);
                                            storageAsyncResult.Result = true;
                                            storageAsyncResult.OnComplete();
                                        }
                                        catch (StorageException e)
                                        {
                                            if (e.RequestInformation.HttpStatusCode == (int)HttpStatusCode.NotFound)
                                            {
                                                if ((e.RequestInformation.ExtendedErrorInformation == null) ||
                                                    (e.RequestInformation.ExtendedErrorInformation.ErrorCode == BlobErrorCodeStrings.BlobNotFound))
                                                {
                                                    storageAsyncResult.Result = false;
                                                    storageAsyncResult.OnComplete();
                                                }
                                                else
                                                {
                                                    storageAsyncResult.OnComplete(e);
                                                }
                                            }
                                            else
                                            {
                                                storageAsyncResult.OnComplete(e);
                                            }
                                        }
                                        catch (Exception e)
                                        {
                                            storageAsyncResult.OnComplete(e);
                                        }
                                    },
                                    null /* state */);

                                storageAsyncResult.CancelDelegate = savedDeleteResult.Cancel;
                                if (storageAsyncResult.CancelRequested)
                                {
                                    storageAsyncResult.Cancel();
                                }
                            }
                            catch (Exception e)
                            {
                                storageAsyncResult.OnComplete(e);
                            }
                        }
                    },
                    null /* state */);

                storageAsyncResult.CancelDelegate = savedExistsResult.Cancel;
                if (storageAsyncResult.CancelRequested)
                {
                    storageAsyncResult.Cancel();
                }
            }
        }
예제 #10
0
        internal ICancellableAsyncResult BeginUploadFromStreamHelper(Stream source, long? length, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state)
        {
            CommonUtility.AssertNotNull("source", source);

            if (!source.CanSeek)
            {
                throw new InvalidOperationException();
            }

            if (length.HasValue)
            {
                CommonUtility.AssertInBounds("length", (long)length, 1, source.Length - source.Position);
            }
            else
            {
                length = source.Length - source.Position;
            }

            if ((length % Constants.PageSize) != 0)
            {
                throw new ArgumentException(SR.InvalidPageSize, "source");
            }

            this.attributes.AssertNoSnapshot();
            BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, BlobType.PageBlob, this.ServiceClient);

            ExecutionState<NullType> tempExecutionState = CommonUtility.CreateTemporaryExecutionState(modifiedOptions);
            StorageAsyncResult<NullType> storageAsyncResult = new StorageAsyncResult<NullType>(callback, state);

            ICancellableAsyncResult result = this.BeginOpenWrite(
                length,
                accessCondition,
                modifiedOptions,
                operationContext,
                ar =>
                {
                    storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);

                    lock (storageAsyncResult.CancellationLockerObject)
                    {
                        storageAsyncResult.CancelDelegate = null;
                        try
                        {
                            CloudBlobStream blobStream = this.EndOpenWrite(ar);
                            storageAsyncResult.OperationState = blobStream;

                            source.WriteToAsync(
                                blobStream,
                                length,
                                null /* maxLength */,
                                false,
                                tempExecutionState,
                                null /* streamCopyState */,
                                completedState =>
                                {
                                    storageAsyncResult.UpdateCompletedSynchronously(completedState.CompletedSynchronously);
                                    if (completedState.ExceptionRef != null)
                                    {
                                        storageAsyncResult.OnComplete(completedState.ExceptionRef);
                                    }
                                    else
                                    {
                                        try
                                        {
                                            lock (storageAsyncResult.CancellationLockerObject)
                                            {
                                                storageAsyncResult.CancelDelegate = null;
                                                ICancellableAsyncResult commitResult = blobStream.BeginCommit(
                                                        CloudBlob.BlobOutputStreamCommitCallback,
                                                        storageAsyncResult);

                                                storageAsyncResult.CancelDelegate = commitResult.Cancel;
                                                if (storageAsyncResult.CancelRequested)
                                                {
                                                    storageAsyncResult.Cancel();
                                                }
                                            }
                                        }
                                        catch (Exception e)
                                        {
                                            storageAsyncResult.OnComplete(e);
                                        }
                                    }
                                });

                            storageAsyncResult.CancelDelegate = tempExecutionState.Cancel;
                            if (storageAsyncResult.CancelRequested)
                            {
                                storageAsyncResult.Cancel();
                            }
                        }
                        catch (Exception e)
                        {
                            storageAsyncResult.OnComplete(e);
                        }
                    }
                },
                null /* state */);

            // We do not need to do this inside a lock, as storageAsyncResult is
            // not returned to the user yet.
            storageAsyncResult.CancelDelegate = result.Cancel;

            return storageAsyncResult;
        }
예제 #11
0
        internal ICancellableAsyncResult BeginUploadFromStreamHelper(Stream source, long? length, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state)
        {
            CommonUtility.AssertNotNull("source", source);

            if (length.HasValue)
            {
                CommonUtility.AssertInBounds("length", length.Value, 1);

                if (source.CanSeek && length > source.Length - source.Position)
                {
                    throw new ArgumentOutOfRangeException("length", SR.StreamLengthShortError);
                }
            }

            this.attributes.AssertNoSnapshot();
            BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, BlobType.BlockBlob, this.ServiceClient);

            ExecutionState<NullType> tempExecutionState = CommonUtility.CreateTemporaryExecutionState(modifiedOptions);
            StorageAsyncResult<NullType> storageAsyncResult = new StorageAsyncResult<NullType>(callback, state);

            bool lessThanSingleBlobThreshold = CloudBlockBlob.IsLessThanSingleBlobThreshold(source, length, modifiedOptions, false);
            modifiedOptions.AssertPolicyIfRequired();
            
            if (modifiedOptions.ParallelOperationThreadCount.Value == 1 && lessThanSingleBlobThreshold)
            {
                // Because we may or may not want to calculate the MD5, and we may or may not want to encrypt, rather than have four branching code
                // paths, here we have an action that we will run, which continually gets added to, depending on which operations we need to do.
                // The confusing part is that we have to build it from the bottom up.

                string md5 = null;
                Stream sourceStream = source;
                Action actionToRun = null;

                Action uploadAction = () =>
                    {
                        if (md5 == null && modifiedOptions.UseTransactionalMD5.Value)
                        {
                            throw new ArgumentException(SR.PutBlobNeedsStoreBlobContentMD5, "options");
                        }

                        this.UploadFromStreamHandler(
                                            sourceStream,
                                            length,
                                            md5,
                                            accessCondition,
                                            operationContext,
                                            modifiedOptions,
                                            storageAsyncResult);

                    };
                actionToRun = uploadAction;

                if (modifiedOptions.StoreBlobContentMD5.Value)
                {
                    Action<Action> calculateMD5 = (continuation) =>
                    {
                        long startPosition = sourceStream.Position;
                        StreamDescriptor streamCopyState = new StreamDescriptor();
                        sourceStream.WriteToAsync(
                            Stream.Null,
                            length,
                            null /* maxLength */,
                            true,
                            tempExecutionState,
                            streamCopyState,
                            completedState =>
                            {
                                ContinueAsyncOperation(storageAsyncResult, completedState, () =>
                                    {
                                        if (completedState.ExceptionRef != null)
                                        {
                                            storageAsyncResult.OnComplete(completedState.ExceptionRef);
                                        }
                                        else
                                        {
                                            sourceStream.Position = startPosition;
                                            md5 = streamCopyState.Md5;
                                            continuation();
                                        }
                                    });
                            });

                        storageAsyncResult.CancelDelegate = tempExecutionState.Cancel;
                        if (storageAsyncResult.CancelRequested)
                        {
                            storageAsyncResult.Cancel();
                        }
                    };
                    Action oldActionToRun = actionToRun;
                    actionToRun = () => calculateMD5(oldActionToRun);
                }

                if (modifiedOptions.EncryptionPolicy != null)
                {
                    Action<Action> encryptStream = continuation =>
                        {
                            SyncMemoryStream syncMemoryStream = new SyncMemoryStream();
                            options.AssertPolicyIfRequired();

                            sourceStream = syncMemoryStream;

                            if (modifiedOptions.EncryptionPolicy.EncryptionMode != BlobEncryptionMode.FullBlob)
                            {
                                throw new InvalidOperationException(SR.InvalidEncryptionMode, null);
                            }

                            ICryptoTransform transform = options.EncryptionPolicy.CreateAndSetEncryptionContext(this.Metadata, false /* noPadding */);
                            CryptoStream cryptoStream = new CryptoStream(syncMemoryStream, transform, CryptoStreamMode.Write);
                            StreamDescriptor streamCopyState = new StreamDescriptor();

                            source.WriteToAsync(cryptoStream, length, null, false, tempExecutionState, streamCopyState, completedState =>
                                {
                                    ContinueAsyncOperation(storageAsyncResult, completedState, () =>
                                        {
                                            if (completedState.ExceptionRef != null)
                                            {
                                                storageAsyncResult.OnComplete(completedState.ExceptionRef);
                                            }
                                            else
                                            {
                                                // Flush the CryptoStream in order to make sure that the last block of data is flushed. This call is a sync call
                                                // but it is ok to have it because we're just writing to a memory stream.
                                                cryptoStream.FlushFinalBlock();

                                                // After the tempStream has been written to, we need to seek back to the beginning, so that it can be read from.
                                                sourceStream.Seek(0, SeekOrigin.Begin);
                                                length = syncMemoryStream.Length;
                                                continuation();
                                            }
                                        });
                                });

                            storageAsyncResult.CancelDelegate = tempExecutionState.Cancel;
                            if (storageAsyncResult.CancelRequested)
                            {
                                storageAsyncResult.Cancel();
                            }
                        };
                    Action oldActionToRun = actionToRun;
                    actionToRun = () => encryptStream(oldActionToRun);
                }

                actionToRun();
            }
            else
            {
                ICancellableAsyncResult result = this.BeginOpenWrite(
                    accessCondition,
                    modifiedOptions,
                    operationContext,
                    ar =>
                    {
                        ContinueAsyncOperation(storageAsyncResult, ar, () =>
                            {
                                CloudBlobStream blobStream = this.EndOpenWrite(ar);
                                storageAsyncResult.OperationState = blobStream;

                                source.WriteToAsync(
                                    blobStream,
                                    length,
                                    null /* maxLength */,
                                    false,
                                    tempExecutionState,
                                    null /* streamCopyState */,
                                    completedState =>
                                    {
                                        ContinueAsyncOperation(storageAsyncResult, completedState, () =>
                                        {
                                            if (completedState.ExceptionRef != null)
                                            {
                                                storageAsyncResult.OnComplete(completedState.ExceptionRef);
                                            }
                                            else
                                            {
                                                ICancellableAsyncResult commitResult = blobStream.BeginCommit(
                                                        CloudBlob.BlobOutputStreamCommitCallback,
                                                        storageAsyncResult);

                                                storageAsyncResult.CancelDelegate = commitResult.Cancel;
                                                if (storageAsyncResult.CancelRequested)
                                                {
                                                    storageAsyncResult.Cancel();
                                                }
                                            }
                                        });
                                    });

                                storageAsyncResult.CancelDelegate = tempExecutionState.Cancel;
                                if (storageAsyncResult.CancelRequested)
                                {
                                    storageAsyncResult.Cancel();
                                }
                            });
                    },
                    null /* state */);

                // We do not need to do this inside a lock, as storageAsyncResult is
                // not returned to the user yet.
                storageAsyncResult.CancelDelegate = result.Cancel;
            }

            return storageAsyncResult;
        }
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            StorageAsyncResult<NullType> result = new StorageAsyncResult<NullType>(callback, state);

            if (this.completeSynchronously)
            {
                result.UpdateCompletedSynchronously(this.completeSynchronously);
                try
                {
                    this.Write(buffer, offset, count);
                    result.OnComplete();
                }
                catch (Exception e)
                {
                    result.OnComplete(e);
                }
            }
            else
            {
                ThreadPool.QueueUserWorkItem(_ =>
                    {
                        result.UpdateCompletedSynchronously(this.completeSynchronously);
                        try
                        {
                            this.Write(buffer, offset, count);
                            result.OnComplete();
                        }
                        catch (Exception e)
                        {
                            result.OnComplete(e);
                        }
                    },
                    null);
            }

            return result;
        }
        private void WriteRange(Stream rangeData, long offset, string contentMD5, StorageAsyncResult<NullType> asyncResult)
        {
            this.noPendingWritesEvent.Increment();

            this.parallelOperationSemaphore.WaitAsync(calledSynchronously =>
            {
                try
                {
                    ICancellableAsyncResult result = this.file.BeginWriteRange(
                        rangeData,
                        offset,
                        contentMD5,
                        this.accessCondition,
                        this.options,
                        this.operationContext,
                        this.WriteRangeCallback,
                        null /* state */);

                    if (asyncResult != null)
                    {
                        // We do not need to do this inside a lock, as asyncResult is
                        // not returned to the user yet.
                        asyncResult.CancelDelegate = result.Cancel;
                    }
                }
                catch (Exception e)
                {
                    this.lastException = e;
                }
                finally
                {
                    if (asyncResult != null)
                    {
                        asyncResult.UpdateCompletedSynchronously(calledSynchronously);
                        asyncResult.OnComplete(this.lastException);
                    }
                }
            });
        }
        public override ICancellableAsyncResult BeginFlush(AsyncCallback callback, object state)
        {
            if (this.committed)
            {
                throw new InvalidOperationException(SR.FileStreamAlreadyCommitted);
            }

            if (this.flushPending)
            {
                // We cannot allow more than one BeginFlush at a time, because
                // RegisterWaitForSingleObject would need duplicated handles
                // of noPendingWritesEvent for each call.
                throw new InvalidOperationException(SR.FileStreamFlushPending);
            }

            try
            {
                this.flushPending = true;
                this.DispatchWrite(null /* asyncResult */);

                StorageAsyncResult<NullType> storageAsyncResult = new StorageAsyncResult<NullType>(callback, state);
                if ((this.lastException != null) || this.noPendingWritesEvent.Wait(0))
                {
                    storageAsyncResult.OnComplete(this.lastException);
                }
                else
                {
                    RegisteredWaitHandle waitHandle = ThreadPool.RegisterWaitForSingleObject(
                        this.noPendingWritesEvent.WaitHandle,
                        this.WaitForPendingWritesCallback,
                        storageAsyncResult,
                        -1,
                        true);

                    storageAsyncResult.OperationState = waitHandle;
                    storageAsyncResult.CancelDelegate = () =>
                    {
                        waitHandle.Unregister(null /* waitObject */);
                        storageAsyncResult.OnComplete(this.lastException);
                    };
                }

                return storageAsyncResult;
            }
            catch (Exception)
            {
                this.flushPending = false;
                throw;
            }
        }
        /// <summary>
        /// Dispatches a write operation.
        /// </summary>
        /// <param name="asyncResult">The reference to the pending asynchronous request to finish.</param>
        private void DispatchWrite(StorageAsyncResult<NullType> asyncResult)
        {
            if (this.internalBuffer.Length == 0)
            {
                if (asyncResult != null)
                {
                    asyncResult.OnComplete(this.lastException);
                }

                return;
            }

            MultiBufferMemoryStream bufferToUpload = this.internalBuffer;
            this.internalBuffer = new MultiBufferMemoryStream(this.Blob.ServiceClient.BufferManager);
            bufferToUpload.Seek(0, SeekOrigin.Begin);

            string bufferMD5 = null;
            if (this.blockMD5 != null)
            {
                bufferMD5 = this.blockMD5.ComputeHash();
                this.blockMD5.Dispose();
                this.blockMD5 = new MD5Wrapper();
            }

            if (this.blockBlob != null)
            {
                string blockId = this.GetCurrentBlockId();
                this.blockList.Add(blockId);
                this.WriteBlock(bufferToUpload, blockId, bufferMD5, asyncResult);
            }
            else
            {
                if ((bufferToUpload.Length % Constants.PageSize) != 0)
                {
                    this.lastException = new IOException(SR.InvalidPageSize);
                    throw this.lastException;
                }

                long offset = this.currentPageOffset;
                this.currentPageOffset += bufferToUpload.Length;
                this.WritePages(bufferToUpload, offset, bufferMD5, asyncResult);
            }
        }
        private void DeleteIfExistsHandler(AccessCondition accessCondition, FileRequestOptions options, OperationContext operationContext, StorageAsyncResult<bool> storageAsyncResult)
        {
            ICancellableAsyncResult savedExistsResult = this.BeginExists(
                options,
                operationContext,
                existsResult =>
                {
                    storageAsyncResult.UpdateCompletedSynchronously(existsResult.CompletedSynchronously);
                    lock (storageAsyncResult.CancellationLockerObject)
                    {
                        storageAsyncResult.CancelDelegate = null;
                        try
                        {
                            bool exists = this.EndExists(existsResult);
                            if (!exists)
                            {
                                storageAsyncResult.Result = false;
                                storageAsyncResult.OnComplete();
                                return;
                            }
                        }
                        catch (Exception e)
                        {
                            storageAsyncResult.OnComplete(e);
                            return;
                        }

                        ICancellableAsyncResult savedDeleteResult = this.BeginDelete(
                            accessCondition,
                            options,
                            operationContext,
                            deleteResult =>
                            {
                                storageAsyncResult.UpdateCompletedSynchronously(deleteResult.CompletedSynchronously);
                                storageAsyncResult.CancelDelegate = null;
                                try
                                {
                                    this.EndDelete(deleteResult);
                                    storageAsyncResult.Result = true;
                                    storageAsyncResult.OnComplete();
                                }
                                catch (StorageException e)
                                {
                                    if (e.RequestInformation.HttpStatusCode == (int)HttpStatusCode.NotFound)
                                    {
                                        storageAsyncResult.Result = false;
                                        storageAsyncResult.OnComplete();
                                    }
                                    else
                                    {
                                        storageAsyncResult.OnComplete(e);
                                    }
                                }
                                catch (Exception e)
                                {
                                    storageAsyncResult.OnComplete(e);
                                }
                            },
                            null);

                        storageAsyncResult.CancelDelegate = savedDeleteResult.Cancel;
                        if (storageAsyncResult.CancelRequested)
                        {
                            storageAsyncResult.Cancel();
                        }
                    }
                },
                null);

            // We do not need to do this inside a lock, as storageAsyncResult is
            // not returned to the user yet.
            storageAsyncResult.CancelDelegate = savedExistsResult.Cancel;
        }
        private void CreateIfNotExistsHandler(FileRequestOptions options, OperationContext operationContext, StorageAsyncResult<bool> storageAsyncResult)
        {
            ICancellableAsyncResult savedExistsResult = this.BeginExists(
                options,
                operationContext,
                existsResult =>
                {
                    storageAsyncResult.UpdateCompletedSynchronously(existsResult.CompletedSynchronously);
                    lock (storageAsyncResult.CancellationLockerObject)
                    {
                        storageAsyncResult.CancelDelegate = null;
                        try
                        {
                            bool exists = this.EndExists(existsResult);
                            if (exists)
                            {
                                storageAsyncResult.Result = false;
                                storageAsyncResult.OnComplete();
                                return;
                            }
                        }
                        catch (Exception e)
                        {
                            storageAsyncResult.OnComplete(e);
                            return;
                        }

                        ICancellableAsyncResult savedCreateResult = this.BeginCreate(
                            options,
                            operationContext,
                            createResult =>
                            {
                                storageAsyncResult.UpdateCompletedSynchronously(createResult.CompletedSynchronously);
                                storageAsyncResult.CancelDelegate = null;
                                try
                                {
                                    this.EndCreate(createResult);
                                    storageAsyncResult.Result = true;
                                    storageAsyncResult.OnComplete();
                                }
                                catch (StorageException e)
                                {
                                    if ((e.RequestInformation.ExtendedErrorInformation != null) &&
                                        (e.RequestInformation.ExtendedErrorInformation.ErrorCode == FileErrorCodeStrings.ResourceAlreadyExists))
                                    {
                                        storageAsyncResult.Result = false;
                                        storageAsyncResult.OnComplete();
                                    }
                                    else
                                    {
                                        storageAsyncResult.OnComplete(e);
                                    }
                                }
                                catch (Exception e)
                                {
                                    storageAsyncResult.OnComplete(e);
                                }
                            },
                            null);

                        storageAsyncResult.CancelDelegate = savedCreateResult.Cancel;
                        if (storageAsyncResult.CancelRequested)
                        {
                            storageAsyncResult.Cancel();
                        }
                    }
                },
                null);

            // We do not need to do this inside a lock, as storageAsyncResult is
            // not returned to the user yet.
            storageAsyncResult.CancelDelegate = savedExistsResult.Cancel;
        }
        /// <summary>
        /// Begins an asynchronous read operation.
        /// </summary>
        /// <param name="buffer">When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source.</param>
        /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream.</param>
        /// <param name="count">The maximum number of bytes to be read.</param>
        /// <param name="callback">An optional asynchronous callback, to be called when the read is complete.</param>
        /// <param name="state">A user-provided object that distinguishes this particular asynchronous read request from other requests.</param>
        /// <returns>An IAsyncResult that represents the asynchronous read, which could still be pending.</returns>
        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            if (count < 0)
            {
                throw new ArgumentOutOfRangeException("count");
            }

            long remainingBytes = this.Length > this.Position ? this.Length - this.Position : 0;
            if (count > remainingBytes)
            {
                count = (int)remainingBytes;
            }

            StorageAsyncResult<int> storageAsyncResult = new StorageAsyncResult<int>(callback, state);
            if (count == 0)
            {
                storageAsyncResult.Result = 0;
                storageAsyncResult.OnComplete();
                return storageAsyncResult;
            }
            else
            {
                return this.wrappedStream.BeginRead(buffer, offset, count, callback, state);
            }
        }
        private void PutBlockHandler(string blockId, Stream blockData, string contentMD5, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, StorageAsyncResult<NullType> storageAsyncResult)
        {
            lock (storageAsyncResult.CancellationLockerObject)
            {
                ICancellableAsyncResult result = Executor.BeginExecuteAsync(
                    this.PutBlockImpl(blockData, blockId, contentMD5, accessCondition, options),
                    options.RetryPolicy,
                    operationContext,
                    ar =>
                    {
                        storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);

                        try
                        {
                            Executor.EndExecuteAsync<NullType>(ar);
                            storageAsyncResult.OnComplete();
                        }
                        catch (Exception e)
                        {
                            storageAsyncResult.OnComplete(e);
                        }
                    },
                    null /* asyncState */);

                storageAsyncResult.CancelDelegate = result.Cancel;
                if (storageAsyncResult.CancelRequested)
                {
                    storageAsyncResult.Cancel();
                }
            }
        }
예제 #20
0
        /// <summary>
        /// Begins an asynchronous write operation.
        /// </summary>
        /// <param name="buffer">An array of bytes. This method copies count bytes from
        /// buffer to the current stream. </param>
        /// <param name="offset">The zero-based byte offset in buffer at which to begin
        /// copying bytes to the current stream.</param>
        /// <param name="count">The number of bytes to be written to the current stream.</param>
        /// <param name="callback">An optional asynchronous callback, to be called when the write is complete.</param>
        /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from other requests.</param>
        /// <returns>An <c>IAsyncResult</c> that represents the asynchronous write, which could still be pending.</returns>
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            CommonUtility.AssertNotNull("buffer", buffer);
            CommonUtility.AssertInBounds("offset", offset, 0, buffer.Length);
            CommonUtility.AssertInBounds("count", count, 0, buffer.Length - offset);

            if (this.committed)
            {
                throw new InvalidOperationException(SR.BlobStreamAlreadyCommitted);
            }

            StorageAsyncResult <NullType> storageAsyncResult = new StorageAsyncResult <NullType>(callback, state);
            StorageAsyncResult <NullType> currentAsyncResult = storageAsyncResult;

            this.currentOffset += count;
            int  initialOffset = offset;
            int  initialCount  = count;
            bool dispatched    = false;

            if (this.lastException == null)
            {
                while (count > 0)
                {
                    int maxBytesToWrite = this.streamWriteSizeInBytes - (int)this.internalBuffer.Length;
                    int bytesToWrite    = Math.Min(count, maxBytesToWrite);

                    this.internalBuffer.Write(buffer, offset, bytesToWrite);
                    if (this.blockMD5 != null)
                    {
                        this.blockMD5.UpdateHash(buffer, offset, bytesToWrite);
                    }

                    count  -= bytesToWrite;
                    offset += bytesToWrite;

                    if (bytesToWrite == maxBytesToWrite)
                    {
                        this.DispatchWrite(currentAsyncResult);
                        dispatched = true;

                        // Do not use the IAsyncResult we are going to return more
                        // than once, as otherwise its callback will be called more
                        // than once.
                        currentAsyncResult = null;
                    }
                }
            }

            // Update transactional, then update full blob, in that order.
            // This way, if there's any bit corruption that happens in between the two, we detect it at PutBlock on the service,
            // rather than GetBlob + validate on the client
            if (this.blobMD5 != null)
            {
                this.blobMD5.UpdateHash(buffer, initialOffset, initialCount);
            }

            if (!dispatched)
            {
                storageAsyncResult.OnComplete(this.lastException);
            }

            return(storageAsyncResult);
        }
        /// <summary>
        /// Begins an asynchronous write operation.
        /// </summary>
        /// <param name="buffer">The buffer to write data from.</param>
        /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param>
        /// <param name="count">The number of bytes to write.</param>
        /// <param name="callback">An optional asynchronous callback, to be called when the write is complete.</param>
        /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from other requests.</param>
        /// <returns>An IAsyncResult that represents the asynchronous write, which could still be pending.</returns>
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            CommonUtility.AssertNotNull("buffer", buffer);
            CommonUtility.AssertInBounds("offset", offset, 0, buffer.Length);
            CommonUtility.AssertInBounds("count", count, 0, buffer.Length - offset);

            StorageAsyncResult<NullType> result = new StorageAsyncResult<NullType>(callback, state);

            try
            {
                this.Write(buffer, offset, count);
                result.OnComplete();
            }
            catch (Exception e)
            {
                result.OnComplete(e);
            }

            return result;
        }
        public ICancellableAsyncResult BeginListBlobsSegmented(string prefix, bool useFlatBlobListing, BlobListingDetails blobListingDetails, int? maxResults, BlobContinuationToken currentToken, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state)
        {
            string containerName;
            string listingPrefix;
            CloudBlobClient.ParseUserPrefix(prefix, out containerName, out listingPrefix);

            CloudBlobContainer container = this.GetContainerReference(containerName);
            StorageAsyncResult<BlobResultSegment> result = new StorageAsyncResult<BlobResultSegment>(callback, state);
            ICancellableAsyncResult asyncResult = container.BeginListBlobsSegmented(
                listingPrefix,
                useFlatBlobListing,
                blobListingDetails,
                maxResults,
                currentToken,
                options,
                operationContext,
                ar =>
                {
                    result.UpdateCompletedSynchronously(ar.CompletedSynchronously);

                    try
                    {
                        result.Result = container.EndListBlobsSegmented(ar);
                        result.OnComplete();
                    }
                    catch (Exception e)
                    {
                        result.OnComplete(e);
                    }
                },
                null /* state */);

            result.CancelDelegate = asyncResult.Cancel;
            return result;
        }
        /// <summary>
        /// Initiates a write operation for the next buffer in line.
        /// </summary>
        /// <param name="result">Internal StorageAsyncResult that represents the asynchronous copy.</param>
        private void FastCopyToInternal(StorageAsyncResult<NullType> result)
        {
            CopyState copyState = (CopyState)result.OperationState;

            // Maximum amount you can read is from current spot to the end.
            long leftToRead = this.Length - this.Position;

            try
            {
                while (leftToRead != 0)
                {
                    if (copyState.ExpiryTime.HasValue && DateTime.Now.CompareTo(copyState.ExpiryTime.Value) > 0)
                    {
                        throw new TimeoutException();
                    }

                    ArraySegment<byte> currentBlock = this.GetCurrentBlock();

                    int blockReadLength = (int)Math.Min(leftToRead, currentBlock.Count);
                    this.AdvancePosition(ref leftToRead, blockReadLength);

                    IAsyncResult asyncResult = copyState.Destination.BeginWrite(currentBlock.Array, currentBlock.Offset, blockReadLength, this.FastCopyToCallback, result);

                    if (!asyncResult.CompletedSynchronously)
                    {
                        return;
                    }

                    copyState.Destination.EndWrite(asyncResult);
                }

                result.OnComplete();
            }
            catch (Exception e)
            {
                if (copyState.ExpiryTime.HasValue && DateTime.Now.CompareTo(copyState.ExpiryTime.Value) > 0)
                {
                    result.OnComplete(new TimeoutException());
                }
                else
                {
                    result.OnComplete(e);
                }
            }
        }
        /// <summary>
        /// Dispatches a write operation.
        /// </summary>
        /// <param name="asyncResult">The reference to the pending asynchronous request to finish.</param>
        private void DispatchWrite(StorageAsyncResult<NullType> asyncResult)
        {
            if (this.internalBuffer.Length == 0)
            {
                if (asyncResult != null)
                {
                    asyncResult.OnComplete(this.lastException);
                }

                return;
            }

            MultiBufferMemoryStream bufferToUpload = this.internalBuffer;
            this.internalBuffer = new MultiBufferMemoryStream(this.file.ServiceClient.BufferManager);
            bufferToUpload.Seek(0, SeekOrigin.Begin);

            string bufferMD5 = null;
            if (this.rangeMD5 != null)
            {
                bufferMD5 = this.rangeMD5.ComputeHash();
                this.rangeMD5.Dispose();
                this.rangeMD5 = new MD5Wrapper();
            }

            long offset = this.currentFileOffset;
            this.currentFileOffset += bufferToUpload.Length;
            this.WriteRange(bufferToUpload, offset, bufferMD5, asyncResult);
        }
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            // Discard bytes at the beginning if required.
            if (this.position < this.startOffset)
            {
                int discardBytes = (int)Math.Min(this.startOffset - this.position, count);
                offset += discardBytes;
                count -= discardBytes;

                this.position += discardBytes;
            }

            // Discard bytes at the end if required.
            if (this.endOffset.HasValue)
            {
                count = (int)Math.Min(this.endOffset.Value + 1 - this.position, count);
            }

            StorageAsyncResult<NullType> storageAsyncResult = new StorageAsyncResult<NullType>(callback, state);
            if (count <= 0)
            {
                storageAsyncResult.OnComplete();
            }
            else
            {
                // If there are any bytes in the buffer left to be written, write to the underlying stream and update position.
                storageAsyncResult.OperationState = count;
                this.wrappedStream.BeginWrite(buffer, offset, count, this.WriteStreamCallback, storageAsyncResult);
            }

            return storageAsyncResult;
        }
        /// <summary>
        /// Begins an asynchronous write operation.
        /// </summary>
        /// <param name="buffer">An array of bytes. This method copies count bytes from
        /// buffer to the current stream. </param>
        /// <param name="offset">The zero-based byte offset in buffer at which to begin
        /// copying bytes to the current stream.</param>
        /// <param name="count">The number of bytes to be written to the current stream.</param>
        /// <param name="callback">An optional asynchronous callback, to be called when the write is complete.</param>
        /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from other requests.</param>
        /// <returns>An <c>IAsyncResult</c> that represents the asynchronous write, which could still be pending.</returns>
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            CommonUtility.AssertNotNull("buffer", buffer);
            CommonUtility.AssertInBounds("offset", offset, 0, buffer.Length);
            CommonUtility.AssertInBounds("count", count, 0, buffer.Length - offset);

            if (this.committed)
            {
                throw new InvalidOperationException(SR.FileStreamAlreadyCommitted);
            }

            if (this.fileMD5 != null)
            {
                this.fileMD5.UpdateHash(buffer, offset, count);
            }

            StorageAsyncResult<NullType> storageAsyncResult = new StorageAsyncResult<NullType>(callback, state);
            StorageAsyncResult<NullType> currentChainedResult = storageAsyncResult;

            this.currentOffset += count;
            bool dispatched = false;
            if (this.lastException == null)
            {
                while (count > 0)
                {
                    int maxBytesToWrite = this.streamWriteSizeInBytes - (int)this.internalBuffer.Length;
                    int bytesToWrite = Math.Min(count, maxBytesToWrite);

                    this.internalBuffer.Write(buffer, offset, bytesToWrite);
                    if (this.rangeMD5 != null)
                    {
                        this.rangeMD5.UpdateHash(buffer, offset, bytesToWrite);
                    }

                    count -= bytesToWrite;
                    offset += bytesToWrite;

                    if (bytesToWrite == maxBytesToWrite)
                    {
                        this.DispatchWrite(currentChainedResult);
                        dispatched = true;

                        // Do not use the IAsyncResult we are going to return more
                        // than once, as otherwise its callback will be called more
                        // than once.
                        currentChainedResult = null;
                    }
                }
            }

            if (!dispatched)
            {
                storageAsyncResult.OnComplete(this.lastException);
            }

            return storageAsyncResult;
        }
예제 #27
0
        public ICancellableAsyncResult BeginOpenWrite(long? size, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state)
        {
            this.attributes.AssertNoSnapshot();
            bool createNew = size.HasValue;
            BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, this.BlobType, this.ServiceClient, false);
           
            StorageAsyncResult<CloudBlobStream> storageAsyncResult = new StorageAsyncResult<CloudBlobStream>(callback, state);
            ICancellableAsyncResult result;
            if (createNew)
            {
                result = this.BeginCreate(
                    size.Value,
                    accessCondition,
                    options,
                    operationContext,
                    ar =>
                    {
                        storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);

                        try
                        {
                            this.EndCreate(ar);

                            if (accessCondition != null)
                            {
                                accessCondition = AccessCondition.GenerateLeaseCondition(accessCondition.LeaseId);
                            }

                            storageAsyncResult.Result = new BlobWriteStream(this, size.Value, createNew, accessCondition, modifiedOptions, operationContext);
                            storageAsyncResult.OnComplete();
                        }
                        catch (Exception e)
                        {
                            storageAsyncResult.OnComplete(e);
                        }
                    },
                    null /* state */);
            }
            else
            {
                if (modifiedOptions.StoreBlobContentMD5.Value)
                {
                    throw new ArgumentException(SR.MD5NotPossible);
                }

                result = this.BeginFetchAttributes(
                    accessCondition,
                    options,
                    operationContext,
                    ar =>
                    {
                        storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);

                        try
                        {
                            this.EndFetchAttributes(ar);

                            if (accessCondition != null)
                            {
                                accessCondition = AccessCondition.GenerateLeaseCondition(accessCondition.LeaseId);
                            }

                            storageAsyncResult.Result = new BlobWriteStream(this, this.Properties.Length, createNew, accessCondition, modifiedOptions, operationContext);
                            storageAsyncResult.OnComplete();
                        }
                        catch (Exception e)
                        {
                            storageAsyncResult.OnComplete(e);
                        }
                    },
                    null /* state */);
            }

            storageAsyncResult.CancelDelegate = result.Cancel;
            return storageAsyncResult;
        }
예제 #28
0
 private static void ContinueAsyncOperation(StorageAsyncResult<NullType> storageAsyncResult, IAsyncResult result, Action actionToTakeInTheLock)
 {
     storageAsyncResult.UpdateCompletedSynchronously(result.CompletedSynchronously);
     try
     {
         lock (storageAsyncResult.CancellationLockerObject)
         {
             storageAsyncResult.CancelDelegate = null;
             actionToTakeInTheLock();
         }
     }
     catch (Exception e)
     {
         storageAsyncResult.OnComplete(e);
     }
 }
        /// <summary>
        /// Begins an asynchronous read operation.
        /// </summary>
        /// <param name="buffer">The buffer to read the data into.</param>
        /// <param name="offset">The byte offset in buffer at which to begin writing
        /// data read from the stream.</param>
        /// <param name="count">The maximum number of bytes to read.</param>
        /// <param name="callback">An optional asynchronous callback, to be called when the read is complete.</param>
        /// <param name="state">A user-provided object that distinguishes this particular asynchronous read request from other requests.</param>
        /// <returns>An <c>IAsyncResult</c> that represents the asynchronous read, which could still be pending.</returns>
        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            CommonUtility.AssertNotNull("buffer", buffer);
            CommonUtility.AssertInBounds("offset", offset, 0, buffer.Length);
            CommonUtility.AssertInBounds("count", count, 0, buffer.Length - offset);

            if (this.readPending)
            {
                throw new InvalidOperationException(SR.BlobStreamReadPending);
            }

            try
            {
                this.readPending = true;
                StorageAsyncResult<int> storageAsyncResult = new StorageAsyncResult<int>(callback, state);

                if (this.lastException != null)
                {
                    storageAsyncResult.OnComplete(this.lastException);
                    return storageAsyncResult;
                }

                if ((this.currentOffset == this.Length) || (count == 0))
                {
                    storageAsyncResult.Result = 0;
                    storageAsyncResult.OnComplete();
                    return storageAsyncResult;
                }

                int readCount = this.ConsumeBuffer(buffer, offset, count);
                if (readCount > 0)
                {
                    storageAsyncResult.Result = readCount;
                    storageAsyncResult.OnComplete();
                    return storageAsyncResult;
                }

                this.DispatchReadAsync(storageAsyncResult, buffer, offset, count);
                return storageAsyncResult;
            }
            catch (Exception)
            {
                this.readPending = false;
                throw;
            }
        }
예제 #30
0
        public ICancellableAsyncResult BeginOpenWrite(long? size, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state)
        {
            this.attributes.AssertNoSnapshot();
            bool createNew = size.HasValue;
            BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, this.BlobType, this.ServiceClient, false);

            StorageAsyncResult<CloudBlobStream> storageAsyncResult = new StorageAsyncResult<CloudBlobStream>(callback, state);
            ICancellableAsyncResult result;

            modifiedOptions.AssertPolicyIfRequired();

            if (createNew)
            {
#if !(WINDOWS_RT || ASPNET_K || PORTABLE)
                ICryptoTransform transform = null;
                if (options != null && options.EncryptionPolicy != null)
                {
#if WINDOWS_PHONE
                    throw new InvalidOperationException(SR.EncryptionNotSupportedForPageBlobsOnPhone);
#else
                    transform = options.EncryptionPolicy.CreateAndSetEncryptionContext(this.Metadata, true /* noPadding */);
#endif
                }
#endif
                result = this.BeginCreate(
                    size.Value,
                    accessCondition,
                    options,
                    operationContext,
                    ar =>
                    {
                        storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);

                        try
                        {
                            this.EndCreate(ar);

                            if (accessCondition != null)
                            {
                                accessCondition = AccessCondition.GenerateLeaseCondition(accessCondition.LeaseId);
                            }

#if !(WINDOWS_RT || ASPNET_K || PORTABLE)
                            if (modifiedOptions.EncryptionPolicy != null)
                            {
                                storageAsyncResult.Result = new BlobEncryptedWriteStream(this, this.Properties.Length, createNew, accessCondition, modifiedOptions, operationContext, transform);
                            }
                            else
#endif
                            {
                                storageAsyncResult.Result = new BlobWriteStream(this, this.Properties.Length, createNew, accessCondition, modifiedOptions, operationContext);
                            }

                            storageAsyncResult.OnComplete();
                        }
                        catch (Exception e)
                        {
                            storageAsyncResult.OnComplete(e);
                        }
                    },
                    null /* state */);
            }
            else
            {
                if (modifiedOptions.StoreBlobContentMD5.Value)
                {
                    throw new ArgumentException(SR.MD5NotPossible);
                }

#if !(WINDOWS_RT || ASPNET_K || PORTABLE)
                if (modifiedOptions.EncryptionPolicy != null)
                {
                    throw new ArgumentException(SR.EncryptionNotSupportedForExistingBlobs);
                }
#endif

                result = this.BeginFetchAttributes(
                    accessCondition,
                    options,
                    operationContext,
                    ar =>
                    {
                        storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);

                        try
                        {
                            this.EndFetchAttributes(ar);

                            if (accessCondition != null)
                            {
                                accessCondition = AccessCondition.GenerateLeaseCondition(accessCondition.LeaseId);
                            }

                            storageAsyncResult.Result = new BlobWriteStream(this, this.Properties.Length, createNew, accessCondition, modifiedOptions, operationContext);
                            storageAsyncResult.OnComplete();
                        }
                        catch (Exception e)
                        {
                            storageAsyncResult.OnComplete(e);
                        }
                    },
                    null /* state */);
            }

            storageAsyncResult.CancelDelegate = result.Cancel;
            return storageAsyncResult;
        }
예제 #31
0
        private void CommitFlushCallback(IAsyncResult ar)
        {
            StorageAsyncResult <NullType> storageAsyncResult = (StorageAsyncResult <NullType>)ar.AsyncState;

            storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);
            this.committed = true;

            lock (storageAsyncResult.CancellationLockerObject)
            {
                storageAsyncResult.CancelDelegate = null;
                try
                {
                    this.EndFlush(ar);

                    if (this.blockBlob != null)
                    {
                        if (this.blobMD5 != null)
                        {
                            this.blockBlob.Properties.ContentMD5 = this.blobMD5.ComputeHash();
                        }

                        ICancellableAsyncResult result = this.blockBlob.BeginPutBlockList(
                            this.blockList,
                            this.accessCondition,
                            this.options,
                            this.operationContext,
                            this.PutBlockListCallback,
                            storageAsyncResult);

                        storageAsyncResult.CancelDelegate = result.Cancel;
                    }
                    else
                    {
                        if (this.blobMD5 != null)
                        {
                            this.Blob.Properties.ContentMD5 = this.blobMD5.ComputeHash();

                            ICancellableAsyncResult result = this.Blob.BeginSetProperties(
                                this.accessCondition,
                                this.options,
                                this.operationContext,
                                this.SetPropertiesCallback,
                                storageAsyncResult);

                            storageAsyncResult.CancelDelegate = result.Cancel;
                        }
                        else
                        {
                            storageAsyncResult.OnComplete();
                        }
                    }

                    if (storageAsyncResult.CancelRequested)
                    {
                        storageAsyncResult.Cancel();
                    }
                }
                catch (Exception e)
                {
                    this.lastException = e;
                    storageAsyncResult.OnComplete(e);
                }
            }
        }
        /// <summary>
        /// Begins an asynchronous operation to open a stream for writing to the blob.
        /// </summary>
        /// <param name="accessCondition">An <see cref="AccessCondition"/> object that represents the access conditions for the blob. If <c>null</c>, no condition is used.</param>
        /// <param name="options">A <see cref="BlobRequestOptions"/> object that specifies any additional options for the request.</param>
        /// <param name="operationContext">An <see cref="OperationContext"/> object that represents the context for the current operation.</param>
        /// <param name="callback">The callback delegate that will receive notification when the asynchronous operation completes.</param>
        /// <param name="state">A user-defined object that will be passed to the callback delegate.</param>
        /// <returns>An <see cref="ICancellableAsyncResult"/> that references the asynchronous operation.</returns>
        public ICancellableAsyncResult BeginOpenWrite(AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state)
        {
            this.attributes.AssertNoSnapshot();

            StorageAsyncResult<CloudBlobStream> storageAsyncResult = new StorageAsyncResult<CloudBlobStream>(callback, state);
            BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, this.BlobType, this.ServiceClient, false);

            if ((accessCondition != null) && accessCondition.IsConditional)
            {
                ICancellableAsyncResult result = this.BeginFetchAttributes(
                    accessCondition,
                    options,
                    operationContext,
                    ar =>
                    {
                        storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);

                        try
                        {
                            this.EndFetchAttributes(ar);
                        }
                        catch (StorageException e)
                        {
                            if ((e.RequestInformation != null) &&
                                (e.RequestInformation.HttpStatusCode == (int)HttpStatusCode.NotFound) &&
                                string.IsNullOrEmpty(accessCondition.IfMatchETag))
                            {
                                // If we got a 404 and the condition was not an If-Match,
                                // we should continue with the operation.
                            }
                            else
                            {
                                storageAsyncResult.OnComplete(e);
                                return;
                            }
                        }
                        catch (Exception e)
                        {
                            storageAsyncResult.OnComplete(e);
                            return;
                        }

                        storageAsyncResult.Result = new BlobWriteStream(this, accessCondition, modifiedOptions, operationContext);
                        storageAsyncResult.OnComplete();
                    },
                    null /* state */);

                storageAsyncResult.CancelDelegate = result.Cancel;
            }
            else
            {
                storageAsyncResult.Result = new BlobWriteStream(this, accessCondition, modifiedOptions, operationContext);
                storageAsyncResult.OnComplete();
            }

            return storageAsyncResult;
        }
        private void UploadFromStreamHandler(Stream source, long? length, string contentMD5, AccessCondition accessCondition, OperationContext operationContext, BlobRequestOptions options, StorageAsyncResult<NullType> storageAsyncResult)
        {
            ICancellableAsyncResult result = Executor.BeginExecuteAsync(
                this.PutBlobImpl(source, length, contentMD5, accessCondition, options),
                options.RetryPolicy,
                operationContext,
                ar =>
                {
                    storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);

                    try
                    {
                        Executor.EndExecuteAsync<NullType>(ar);
                        storageAsyncResult.OnComplete();
                    }
                    catch (Exception e)
                    {
                        storageAsyncResult.OnComplete(e);
                    }
                },
                null /* asyncState */);

            storageAsyncResult.CancelDelegate = result.Cancel;
            if (storageAsyncResult.CancelRequested)
            {
                storageAsyncResult.Cancel();
            }
        }
        public ICancellableAsyncResult BeginPutBlock(string blockId, Stream blockData, string contentMD5, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state)
        {
            CommonUtility.AssertNotNull("blockData", blockData);

            BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, BlobType.BlockBlob, this.ServiceClient);
            bool requiresContentMD5 = (contentMD5 == null) && modifiedOptions.UseTransactionalMD5.Value;
            operationContext = operationContext ?? new OperationContext();
            StorageAsyncResult<NullType> storageAsyncResult = new StorageAsyncResult<NullType>(callback, state);

            if (blockData.CanSeek && !requiresContentMD5)
            {
                this.PutBlockHandler(blockId, blockData, contentMD5, accessCondition, modifiedOptions, operationContext, storageAsyncResult);
            }
            else
            {
                ExecutionState<NullType> tempExecutionState = CommonUtility.CreateTemporaryExecutionState(modifiedOptions);
                storageAsyncResult.CancelDelegate = tempExecutionState.Cancel;

                Stream seekableStream;
                Stream writeToStream;
                if (blockData.CanSeek)
                {
                    seekableStream = blockData;
                    writeToStream = Stream.Null;
                }
                else
                {
                    seekableStream = new MultiBufferMemoryStream(this.ServiceClient.BufferManager);
                    writeToStream = seekableStream;
                }

                long startPosition = seekableStream.Position;
                StreamDescriptor streamCopyState = new StreamDescriptor();
                blockData.WriteToAsync(
                    writeToStream,
                    null /* copyLength */,
                    Constants.MaxBlockSize,
                    requiresContentMD5,
                    tempExecutionState,
                    streamCopyState,
                    completedState =>
                    {
                        storageAsyncResult.UpdateCompletedSynchronously(completedState.CompletedSynchronously);

                        if (completedState.ExceptionRef != null)
                        {
                            storageAsyncResult.OnComplete(completedState.ExceptionRef);
                        }
                        else
                        {
                            try
                            {
                                if (requiresContentMD5)
                                {
                                    contentMD5 = streamCopyState.Md5;
                                }

                                seekableStream.Position = startPosition;
                                this.PutBlockHandler(blockId, seekableStream, contentMD5, accessCondition, modifiedOptions, operationContext, storageAsyncResult);
                            }
                            catch (Exception e)
                            {
                                storageAsyncResult.OnComplete(e);
                            }
                        }
                    });
            }

            return storageAsyncResult;
        }
        /// <summary>
        /// Starts an asynchronous AppendBlock operation as soon as the parallel
        /// operation semaphore becomes available. Since parallelism is always set
        /// to 1 for append blobs, appendblock operations are called serially.
        /// </summary>
        /// <param name="blockData">Data to be uploaded.</param>
        /// <param name="offset">Offset within the append blob to be used to set the append offset conditional header.</param>
        /// <param name="blockMD5">MD5 hash of the data to be uploaded.</param>
        /// <param name="asyncResult">The reference to the pending asynchronous request to finish.</param>
        private void WriteAppendBlock(Stream blockData, long offset, string blockMD5, StorageAsyncResult<NullType> asyncResult)
        {
            this.noPendingWritesEvent.Increment();
            this.parallelOperationSemaphore.WaitAsync(calledSynchronously =>
            {
                try
                {
                    this.accessCondition.IfAppendPositionEqual = offset;

                    int previousResultsCount = this.operationContext.RequestResults.Count;
                    ICancellableAsyncResult result = this.appendBlob.BeginAppendBlock(
                        blockData, 
                        blockMD5,
                        this.accessCondition,
                        this.options,
                        this.operationContext,
                        this.AppendBlockCallback,
                        previousResultsCount /* state */);

                    if (asyncResult != null)
                    {
                        // We do not need to do this inside a lock, as asyncResult is
                        // not returned to the user yet.
                        asyncResult.CancelDelegate = result.Cancel;
                    }
                }
                catch (Exception e)
                {
                    this.lastException = e;
                    this.noPendingWritesEvent.Decrement();
                    this.parallelOperationSemaphore.Release();
                }
                finally
                {
                    if (asyncResult != null)
                    {
                        asyncResult.UpdateCompletedSynchronously(calledSynchronously);
                        asyncResult.OnComplete(this.lastException);
                    }
                }
            });
        }
        internal ICancellableAsyncResult BeginUploadFromStreamHelper(Stream source, long? length, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state)
        {
            CommonUtility.AssertNotNull("source", source);

            if (length.HasValue)
            {
                CommonUtility.AssertInBounds("length", length.Value, 1);

                if (source.CanSeek && length > source.Length - source.Position)
                {
                    throw new ArgumentOutOfRangeException("length", SR.StreamLengthShortError);
                }
            }

            this.attributes.AssertNoSnapshot();
            BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, BlobType.BlockBlob, this.ServiceClient);

            ExecutionState<NullType> tempExecutionState = CommonUtility.CreateTemporaryExecutionState(modifiedOptions);
            StorageAsyncResult<NullType> storageAsyncResult = new StorageAsyncResult<NullType>(callback, state);

            bool lessThanSingleBlobThreshold = source.CanSeek &&
                (length ?? source.Length - source.Position) <= this.ServiceClient.SingleBlobUploadThresholdInBytes;
            if (this.ServiceClient.ParallelOperationThreadCount == 1 && lessThanSingleBlobThreshold)
            {
                if (modifiedOptions.StoreBlobContentMD5.Value)
                {
                    long startPosition = source.Position;
                    StreamDescriptor streamCopyState = new StreamDescriptor();
                    source.WriteToAsync(
                        Stream.Null,
                        length,
                        null /* maxLength */,
                        true,
                        tempExecutionState,
                        streamCopyState,
                        completedState =>
                        {
                            storageAsyncResult.UpdateCompletedSynchronously(completedState.CompletedSynchronously);

                            try
                            {
                                lock (storageAsyncResult.CancellationLockerObject)
                                {
                                    storageAsyncResult.CancelDelegate = null;
                                    if (completedState.ExceptionRef != null)
                                    {
                                        storageAsyncResult.OnComplete(completedState.ExceptionRef);
                                    }
                                    else
                                    {
                                        source.Position = startPosition;
                                        this.UploadFromStreamHandler(
                                            source,
                                            length,
                                            streamCopyState.Md5,
                                            accessCondition,
                                            operationContext,
                                            modifiedOptions,
                                            storageAsyncResult);
                                    }
                                }
                            }
                            catch (Exception e)
                            {
                                storageAsyncResult.OnComplete(e);
                            }
                        });

                    // We do not need to do this inside a lock, as storageAsyncResult is
                    // not returned to the user yet.
                    storageAsyncResult.CancelDelegate = tempExecutionState.Cancel;
                }
                else
                {
                    if (modifiedOptions.UseTransactionalMD5.Value)
                    {
                        throw new ArgumentException(SR.PutBlobNeedsStoreBlobContentMD5, "options");
                    }

                    this.UploadFromStreamHandler(
                        source,
                        length,
                        null /* contentMD5 */,
                        accessCondition,
                        operationContext,
                        modifiedOptions,
                        storageAsyncResult);
                }
            }
            else
            {
                ICancellableAsyncResult result = this.BeginOpenWrite(
                    accessCondition,
                    modifiedOptions,
                    operationContext,
                    ar =>
                    {
                        storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);

                        lock (storageAsyncResult.CancellationLockerObject)
                        {
                            storageAsyncResult.CancelDelegate = null;
                            try
                            {
                                CloudBlobStream blobStream = this.EndOpenWrite(ar);
                                storageAsyncResult.OperationState = blobStream;

                                source.WriteToAsync(
                                    blobStream,
                                    length,
                                    null /* maxLength */,
                                    false,
                                    tempExecutionState,
                                    null /* streamCopyState */,
                                    completedState =>
                                    {
                                        storageAsyncResult.UpdateCompletedSynchronously(completedState.CompletedSynchronously);
                                        if (completedState.ExceptionRef != null)
                                        {
                                            storageAsyncResult.OnComplete(completedState.ExceptionRef);
                                        }
                                        else
                                        {
                                            try
                                            {
                                                lock (storageAsyncResult.CancellationLockerObject)
                                                {
                                                    storageAsyncResult.CancelDelegate = null;
                                                    ICancellableAsyncResult commitResult = blobStream.BeginCommit(
                                                            CloudBlobSharedImpl.BlobOutputStreamCommitCallback,
                                                            storageAsyncResult);

                                                    storageAsyncResult.CancelDelegate = commitResult.Cancel;
                                                    if (storageAsyncResult.CancelRequested)
                                                    {
                                                        storageAsyncResult.Cancel();
                                                    }
                                                }
                                            }
                                            catch (Exception e)
                                            {
                                                storageAsyncResult.OnComplete(e);
                                            }
                                        }
                                    });

                                storageAsyncResult.CancelDelegate = tempExecutionState.Cancel;
                                if (storageAsyncResult.CancelRequested)
                                {
                                    storageAsyncResult.Cancel();
                                }
                            }
                            catch (Exception e)
                            {
                                storageAsyncResult.OnComplete(e);
                            }
                        }
                    },
                    null /* state */);

                // We do not need to do this inside a lock, as storageAsyncResult is
                // not returned to the user yet.
                storageAsyncResult.CancelDelegate = result.Cancel;
            }

            return storageAsyncResult;
        }
        private void CreateIfNotExistsHandler(BlobContainerPublicAccessType accessType, BlobRequestOptions options, OperationContext operationContext, StorageAsyncResult<bool> storageAsyncResult)
        {
            ICancellableAsyncResult savedExistsResult = this.BeginExists(
                true,
                options,
                operationContext,
                existsResult =>
                {
                    storageAsyncResult.UpdateCompletedSynchronously(existsResult.CompletedSynchronously);
                    lock (storageAsyncResult.CancellationLockerObject)
                    {
                        storageAsyncResult.CancelDelegate = null;
                        try
                        {
                            bool exists = this.EndExists(existsResult);
                            if (exists)
                            {
                                storageAsyncResult.Result = false;
                                storageAsyncResult.OnComplete();
                                return;
                            }

                            ICancellableAsyncResult savedCreateResult = this.BeginCreate(
                                accessType,
                                options,
                                operationContext,
                                createResult =>
                                {
                                    storageAsyncResult.UpdateCompletedSynchronously(createResult.CompletedSynchronously);
                                    storageAsyncResult.CancelDelegate = null;
                                    try
                                    {
                                        this.EndCreate(createResult);
                                        storageAsyncResult.Result = true;
                                        storageAsyncResult.OnComplete();
                                    }
                                    catch (StorageException e)
                                    {
                                        if (e.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict)
                                        {
                                            if ((e.RequestInformation.ExtendedErrorInformation == null) ||
                                                (e.RequestInformation.ExtendedErrorInformation.ErrorCode == BlobErrorCodeStrings.ContainerAlreadyExists))
                                            {
                                                storageAsyncResult.Result = false;
                                                storageAsyncResult.OnComplete();
                                            }
                                            else
                                            {
                                                storageAsyncResult.OnComplete(e);
                                            }
                                        }
                                        else
                                        {
                                            storageAsyncResult.OnComplete(e);
                                        }
                                    }
                                    catch (Exception e)
                                    {
                                        storageAsyncResult.OnComplete(e);
                                    }
                                },
                                null /* state */);

                            storageAsyncResult.CancelDelegate = savedCreateResult.Cancel;
                            if (storageAsyncResult.CancelRequested)
                            {
                                storageAsyncResult.Cancel();
                            }
                        }
                        catch (Exception e)
                        {
                            storageAsyncResult.OnComplete(e);
                        }
                    }
                },
                null /* state */);

            // We do not need to do this inside a lock, as storageAsyncResult is
            // not returned to the user yet.
            storageAsyncResult.CancelDelegate = savedExistsResult.Cancel;
        }
        public virtual ICancellableAsyncResult BeginOpenWrite(bool createNew, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, AsyncCallback callback, object state)
        {
            this.attributes.AssertNoSnapshot();
            BlobRequestOptions modifiedOptions = BlobRequestOptions.ApplyDefaults(options, this.BlobType, this.ServiceClient, false);

            StorageAsyncResult<CloudBlobStream> storageAsyncResult = new StorageAsyncResult<CloudBlobStream>(callback, state);
            ICancellableAsyncResult result;

#if !(WINDOWS_RT || ASPNET_K || PORTABLE)
            ICryptoTransform transform = null;
#endif

            if (createNew)
            {
#if !(WINDOWS_RT || ASPNET_K || PORTABLE)
                if (options != null && options.EncryptionPolicy != null)
                {
                    transform = options.EncryptionPolicy.CreateAndSetEncryptionContext(this.Metadata, false /* noPadding */);
                }
#endif
                result = this.BeginCreateOrReplace(
                    accessCondition,
                    options,
                    operationContext,
                    ar =>
                    {
                        storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);

                        try
                        {
                            this.EndCreateOrReplace(ar);

                            if (accessCondition != null)
                            {
                                accessCondition = new AccessCondition() { LeaseId = accessCondition.LeaseId, IfAppendPositionEqual = accessCondition.IfAppendPositionEqual, IfMaxSizeLessThanOrEqual = accessCondition.IfMaxSizeLessThanOrEqual };
                            }

#if !(WINDOWS_RT || ASPNET_K || PORTABLE)
                            if (modifiedOptions.EncryptionPolicy != null)
                            {
                                storageAsyncResult.Result = new BlobEncryptedWriteStream(this, accessCondition, modifiedOptions, operationContext, transform);
                            }
                            else
#endif
                            {
                                storageAsyncResult.Result = new BlobWriteStream(this, accessCondition, modifiedOptions, operationContext);
                            }

                            storageAsyncResult.OnComplete();
                        }
                        catch (Exception e)
                        {
                            storageAsyncResult.OnComplete(e);
                        }
                    },
                    null /* state */);
            }
            else
            {
                if (modifiedOptions.StoreBlobContentMD5.Value)
                {
                    throw new ArgumentException(SR.MD5NotPossible);
                }

#if !(WINDOWS_RT || ASPNET_K || PORTABLE)
                if (modifiedOptions.EncryptionPolicy != null)
                {
                    throw new ArgumentException(SR.EncryptionNotSupportedForExistingBlobs);
                }
#endif
                // Although we don't need any properties from the service, we should make this call in order to honor the user specified conditional headers
                // while opening an existing stream and to get the append position for an existing blob if user didn't specify one.
                result = this.BeginFetchAttributes(
                    accessCondition,
                    options,
                    operationContext,
                    ar =>
                    {
                        storageAsyncResult.UpdateCompletedSynchronously(ar.CompletedSynchronously);

                        try
                        {
                            this.EndFetchAttributes(ar);

                            if (accessCondition != null)
                            {
                                accessCondition = new AccessCondition() { LeaseId = accessCondition.LeaseId, IfAppendPositionEqual = accessCondition.IfAppendPositionEqual };
                            }

                            storageAsyncResult.Result = new BlobWriteStream(this, accessCondition, modifiedOptions, operationContext);
                            storageAsyncResult.OnComplete();
                        }
                        catch (Exception e)
                        {
                            storageAsyncResult.OnComplete(e);
                        }
                    },
                    null /* state */);
            }

            storageAsyncResult.CancelDelegate = result.Cancel;
            return storageAsyncResult;
        }
        private void WriteBlock(Stream blockData, string blockId, string blockMD5, StorageAsyncResult<NullType> asyncResult)
        {
            this.noPendingWritesEvent.Increment();
            this.parallelOperationSemaphore.WaitAsync(calledSynchronously =>
            {
                try
                {
                    ICancellableAsyncResult result = this.blockBlob.BeginPutBlock(
                        blockId,
                        blockData,
                        blockMD5,
                        this.accessCondition,
                        this.options,
                        this.operationContext,
                        this.PutBlockCallback,
                        null /* state */);

                    if (asyncResult != null)
                    {
                        // We do not need to do this inside a lock, as asyncResult is
                        // not returned to the user yet.
                        asyncResult.CancelDelegate = result.Cancel;
                    }
                }
                catch (Exception e)
                {
                    this.lastException = e;
                    this.noPendingWritesEvent.Decrement();
                    this.parallelOperationSemaphore.Release();
                }
                finally
                {
                    if (asyncResult != null)
                    {
                        asyncResult.UpdateCompletedSynchronously(calledSynchronously);
                        asyncResult.OnComplete(this.lastException);
                    }
                }
            });
        }