private async Task ExecuteWithShimmedWebRequestForBlockBlobsAsync(Dictionary <string, byte[]> simulatedBlobs, Func <Task> body) { // Note how we create the shims context here using (ShimsContext.Create()) { // Azure storage uses IAsyncResult-pattern in the background. Therefore we have to create shims // for Begin/EndGetResponse. BTW - you can check the code of Azure Storage Library at // https://github.com/WindowsAzure/azure-storage-net ShimHttpWebRequest.AllInstances.BeginGetResponseAsyncCallbackObject = (@this, callback, state) => { // Check if the request matches on of the blobs that we should simulate byte[] requestedBlob; if (!simulatedBlobs.TryGetValue(@this.RequestUri.AbsolutePath, out requestedBlob)) { Assert.Fail("Unexpected request for {0}", @this.RequestUri.AbsoluteUri); } // Setup IAsyncResult; note how we use a stub for that. var result = new StubIAsyncResult() { // Azure Storage Library relies on a wait handle. We give one back that is immediately set. AsyncWaitHandleGet = () => new ManualResetEvent(true), // We pass on the state AsyncStateGet = () => state }; // We immediately call the callback as we do not have to wait for a real web request to finish callback(result); return(result); }; ShimHttpWebRequest.AllInstances.EndGetResponseIAsyncResult = (@this, __) => { // Check if the request matches on of the blobs that we should simulate byte[] requestedBlob; if (!simulatedBlobs.TryGetValue(@this.RequestUri.AbsolutePath, out requestedBlob)) { Assert.Fail("Unexpected request for {0}", @this.RequestUri.AbsoluteUri); } // Setup response headers. Read Azure Storage HTTP docs for details // (see http://msdn.microsoft.com/en-us/library/windowsazure/dd179440.aspx) var headers = new WebHeaderCollection(); headers.Add("Accept-Ranges", "bytes"); headers.Add("ETag", "0xFFFFFFFFFFFFFFF"); headers.Add("x-ms-request-id", Guid.NewGuid().ToString()); headers.Add("x-ms-version", "2013-08-15"); headers.Add("x-ms-lease-status", "unlocked"); headers.Add("x-ms-lease-state", "available"); headers.Add("x-ms-blob-type", "BlockBlob"); headers.Add("Date", DateTime.Now.ToString("R", CultureInfo.InvariantCulture)); // Calculate MD5 hash for our blob and add it to the response headers var md5Check = MD5.Create(); md5Check.TransformBlock(requestedBlob, 0, requestedBlob.Length, null, 0); md5Check.TransformFinalBlock(new byte[0], 0, 0); var hashBytes = md5Check.Hash; var hashVal = Convert.ToBase64String(hashBytes); headers.Add("Content-MD5", hashVal); // As the headers are complete, we can now build the shimmed web response return(new ShimHttpWebResponse() { GetResponseStream = () => { // Simulate downloaded bytes return new MemoryStream(requestedBlob); }, // Status code depends on x-ms-range request header // (see Azure Storage HTTP docs for details) StatusCodeGet = () => string.IsNullOrEmpty(@this.Headers["x-ms-range"]) ? HttpStatusCode.OK : HttpStatusCode.PartialContent, HeadersGet = () => headers, ContentLengthGet = () => requestedBlob.Length, ContentTypeGet = () => "application/octet-stream", LastModifiedGet = () => new DateTime(2014, 1, 1) }); }; await body(); } }
private async Task ExecuteWithShimmedWebRequestForBlockBlobsAsync(Dictionary<string, byte[]> simulatedBlobs, Func<Task> body) { // Note how we create the shims context here using (ShimsContext.Create()) { // Azure storage uses IAsyncResult-pattern in the background. Therefore we have to create shims // for Begin/EndGetResponse. BTW - you can check the code of Azure Storage Library at // https://github.com/WindowsAzure/azure-storage-net ShimHttpWebRequest.AllInstances.BeginGetResponseAsyncCallbackObject = (@this, callback, state) => { // Check if the request matches on of the blobs that we should simulate byte[] requestedBlob; if (!simulatedBlobs.TryGetValue(@this.RequestUri.AbsolutePath, out requestedBlob)) { Assert.Fail("Unexpected request for {0}", @this.RequestUri.AbsoluteUri); } // Setup IAsyncResult; note how we use a stub for that. var result = new StubIAsyncResult() { // Azure Storage Library relies on a wait handle. We give one back that is immediately set. AsyncWaitHandleGet = () => new ManualResetEvent(true), // We pass on the state AsyncStateGet = () => state }; // We immediately call the callback as we do not have to wait for a real web request to finish callback(result); return result; }; ShimHttpWebRequest.AllInstances.EndGetResponseIAsyncResult = (@this, __) => { // Check if the request matches on of the blobs that we should simulate byte[] requestedBlob; if (!simulatedBlobs.TryGetValue(@this.RequestUri.AbsolutePath, out requestedBlob)) { Assert.Fail("Unexpected request for {0}", @this.RequestUri.AbsoluteUri); } // Setup response headers. Read Azure Storage HTTP docs for details // (see http://msdn.microsoft.com/en-us/library/windowsazure/dd179440.aspx) var headers = new WebHeaderCollection(); headers.Add("Accept-Ranges", "bytes"); headers.Add("ETag", "0xFFFFFFFFFFFFFFF"); headers.Add("x-ms-request-id", Guid.NewGuid().ToString()); headers.Add("x-ms-version", "2013-08-15"); headers.Add("x-ms-lease-status", "unlocked"); headers.Add("x-ms-lease-state", "available"); headers.Add("x-ms-blob-type", "BlockBlob"); headers.Add("Date", DateTime.Now.ToString("R", CultureInfo.InvariantCulture)); // Calculate MD5 hash for our blob and add it to the response headers var md5Check = MD5.Create(); md5Check.TransformBlock(requestedBlob, 0, requestedBlob.Length, null, 0); md5Check.TransformFinalBlock(new byte[0], 0, 0); var hashBytes = md5Check.Hash; var hashVal = Convert.ToBase64String(hashBytes); headers.Add("Content-MD5", hashVal); // As the headers are complete, we can now build the shimmed web response return new ShimHttpWebResponse() { GetResponseStream = () => { // Simulate downloaded bytes return new MemoryStream(requestedBlob); }, // Status code depends on x-ms-range request header // (see Azure Storage HTTP docs for details) StatusCodeGet = () => string.IsNullOrEmpty(@this.Headers["x-ms-range"]) ? HttpStatusCode.OK : HttpStatusCode.PartialContent, HeadersGet = () => headers, ContentLengthGet = () => requestedBlob.Length, ContentTypeGet = () => "application/octet-stream", LastModifiedGet = () => new DateTime(2014, 1, 1) }; }; await body(); } }