/// <summary> /// Constructs a web request to write or clear a range of pages in a page blob. /// </summary> /// <param name="uri">The absolute URI to the blob.</param> /// <param name="timeout">The server timeout interval.</param> /// <param name="properties">The blob's properties.</param> /// <param name="leaseId">The lease ID, if the blob has an active lease.</param> /// <returns>A web request to use to perform the operation.</returns> public static HttpWebRequest PutPage(Uri uri, int timeout, PutPageProperties properties, string leaseId) { UriQueryBuilder builder = new UriQueryBuilder(); builder.Add(Constants.QueryConstants.Component, "page"); HttpWebRequest request = CreateWebRequest(uri, timeout, builder); request.Method = "PUT"; Request.AddLeaseId(request, leaseId); Request.AddOptionalHeader(request, Constants.HeaderConstants.RangeHeader, properties.Range.ToString()); // Page write is either update or clean; required request.Headers.Add(Constants.HeaderConstants.PageWrite, properties.PageWrite.ToString()); return(request); }
/// <summary> /// Constructs a web request to write or clear a range of pages in a page blob. /// </summary> /// <param name="uri">The absolute URI to the blob.</param> /// <param name="timeout">The server timeout interval.</param> /// <param name="properties">The blob's properties.</param> /// <param name="leaseId">The lease ID, if the blob has an active lease.</param> /// <returns>A web request to use to perform the operation.</returns> public static HttpWebRequest PutPage(Uri uri, int timeout, PutPageProperties properties, string leaseId) { UriQueryBuilder builder = new UriQueryBuilder(); builder.Add(Constants.QueryConstants.Component, "page"); HttpWebRequest request = CreateWebRequest(uri, timeout, builder); request.Method = "PUT"; Request.AddLeaseId(request, leaseId); Request.AddOptionalHeader(request, Constants.HeaderConstants.RangeHeader, properties.Range.ToString()); // Page write is either update or clean; required request.Headers.Add(Constants.HeaderConstants.PageWrite, properties.PageWrite.ToString()); return request; }
/// <summary>Implementation method for the WritePage methods.</summary> /// <param name="pageData">The page data. </param> /// <param name="startOffset">The start offset. </param> /// <param name="sourceStreamPosition">The beginning position of the source stream prior to execution, negative if stream is unseekable. </param> /// <param name="options">An object that specifies any additional options for the request. </param> /// <returns>A <see cref="TaskSequence"/> that writes the pages. </returns> private TaskSequence WritePageImpl( Stream pageData, long startOffset, long sourceStreamPosition, BlobRequestOptions options) { CommonUtils.AssertNotNull("options", options); var length = pageData.Length; // Logic to rewind stream on a retry // For non seekable streams we need a way to detect the retry iteration so as to only attempt to execute once. // The first attempt will have SourceStreamPosition = -1, which means the first iteration on a non seekable stream. // The second attempt will have SourceStreamPosition = -2, anything below -1 is considered an abort. Since the Impl method // does not have an execution context to be aware of what iteration is used the SourceStreamPosition is utilized as counter to // differentiate between the first attempt and a retry. if (sourceStreamPosition >= 0 && pageData.CanSeek) { if (sourceStreamPosition != pageData.Position) { pageData.Seek(sourceStreamPosition, 0); } } else if (sourceStreamPosition < -1) { throw new NotSupportedException( string.Format(CultureInfo.CurrentCulture, SR.CannotRetryNonSeekableStreamError)); } if (startOffset % Constants.PageSize != 0) { CommonUtils.ArgumentOutOfRange("startOffset", startOffset); } var rangeStreamOffset = pageData.CanSeek ? pageData.Position : 0; var properties = new PutPageProperties { Range = new PageRange(startOffset, startOffset + length - rangeStreamOffset - 1), PageWrite = PageWrite.Update, }; if ((1 + properties.Range.EndOffset - properties.Range.StartOffset) % Constants.PageSize != 0 || (1 + properties.Range.EndOffset - properties.Range.StartOffset) == 0) { CommonUtils.ArgumentOutOfRange("pageData", pageData); } var webRequest = ProtocolHelper.GetWebRequest( this.ServiceClient, options, timeout => BlobRequest.PutPage(this.TransformedAddress, timeout, properties, null)); ////BlobRequest.AddMetadata(webRequest, this.Metadata); // Retrieve the stream var requestStreamTask = webRequest.GetRequestStreamAsync(); yield return requestStreamTask; // Copy the data using (var outputStream = requestStreamTask.Result) { var copyTask = new InvokeTaskSequenceTask(() => pageData.WriteTo(outputStream)); yield return copyTask; // Materialize any exceptions var scratch = copyTask.Result; } // signing request needs Size to be set this.ServiceClient.Credentials.SignRequest(webRequest); // Get the response var responseTask = webRequest.GetResponseAsyncWithTimeout(this.ServiceClient, options.Timeout); yield return responseTask; // Parse the response using (var webResponse = responseTask.Result as HttpWebResponse) { this.ParseSizeAndLastModified(webResponse); } }
/// <summary>Implementation method for the ClearPage methods.</summary> /// <param name="startOffset">The start offset. Must be multiples of 512. </param> /// <param name="length">Length of the data range to be cleared. Must be multiples of 512. </param> /// <param name="options">An object that specifies any additional options for the request. </param> /// <returns>A <see cref="TaskSequence"/> that writes the pages. </returns> private TaskSequence ClearPageImpl(long startOffset, long length, BlobRequestOptions options) { CommonUtils.AssertNotNull("options", options); if (startOffset < 0 || startOffset % Constants.PageSize != 0) { CommonUtils.ArgumentOutOfRange("startOffset", startOffset); } if (length <= 0 || length % Constants.PageSize != 0) { CommonUtils.ArgumentOutOfRange("length", length); } var properties = new PutPageProperties { Range = new PageRange(startOffset, startOffset + length - 1), PageWrite = PageWrite.Clear, }; var webRequest = ProtocolHelper.GetWebRequest( this.ServiceClient, options, timeout => BlobRequest.PutPage(this.TransformedAddress, timeout, properties, null)); webRequest.ContentLength = 0; // signing request needs Size to be set this.ServiceClient.Credentials.SignRequest(webRequest); // Get the response var responseTask = webRequest.GetResponseAsyncWithTimeout(this.ServiceClient, options.Timeout); yield return responseTask; // Parse the response using (var webResponse = responseTask.Result as HttpWebResponse) { this.ParseSizeAndLastModified(webResponse); } }