I know this a question that have been asked many times. But I simply cannot get it to work reliably.
I get this exception:
Microsoft.WindowsAzure.Storage.StorageException was unhandled by user code
HResult=-2146233088 Message=The remote server returned an error: NotFound.
Source=Microsoft.WindowsAzure.Storage StackTrace: at Microsoft.WindowsAzure.Storage.Core.Util.StorageAsyncResult\`1.End()
at Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.EndUploadFromStream(IAsyncResult asyncResult) at Microsoft.WindowsAzure.Storage.Core.Util.AsyncExtensions.<>c__DisplayClass4.<CreateCallbackVoid>b__3(IAsyncResult ar)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at MVVMTestApp.View.ShieldCreator.<OnNavigatedFrom>d__7.MoveNext()
InnerException: System.Net.WebException
HResult=-2146233079
Message=The remote server returned an error: NotFound.
Source=Microsoft.WindowsAzure.Storage
StackTrace:
at Microsoft.WindowsAzure.Storage.Shared.Protocol.HttpResponseParsers.ProcessExpectedStatusCodeNoException[T](HttpStatusCode expectedStatusCode, HttpStatusCode actualStatusCode, T retVal, StorageCommandBase\`1 cmd, Exception ex)
at Microsoft.WindowsAzure.Storage.Shared.Protocol.HttpResponseParsers.ProcessExpectedStatusCodeNoException[T](HttpStatusCode expectedStatusCode, HttpWebResponse resp, T retVal, StorageCommandBase\`1 cmd, Exception ex)
at Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.<>c__DisplayClass39.<PutBlobImpl>b__38(RESTCommand`1 cmd, HttpWebResponse resp, Exception ex, OperationContext ctx)
at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.EndGetResponse[T](IAsyncResult getResponseResult)
InnerException: System.Net.WebException
HResult=-2146233079
Message=The remote server returned an error: NotFound.
Source=System.Windows
StackTrace:
at System.Net.Browser.ClientHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
at System.Net.Browser.ClientHttpWebRequest.<>c__DisplayClasse.<EndGetResponse>b__d(Object sendState)
at System.Net.Browser.AsyncHelper.<>c__DisplayClass1.<BeginOnUI>b__0(Object sendState)
InnerException:
The code I am using to upload to the server is:
MemoryStream stream = new MemoryStream();
if (bi != null)
{
WriteableBitmap bmp = new WriteableBitmap((BitmapSource)bi);
bmp.SaveJpeg(stream, bmp.PixelWidth, bmp.PixelHeight, 0, 100);
}
stream.Seek(0, SeekOrigin.Begin);
DTO.PictureStorage uploadImage = new DTO.PictureStorage();
uploadImage.UserId = App.UserInformationID;
uploadImage.ContainerName = ("crestimage" + App.UserInformationID.Replace(":", "")).ToLower();
uploadImage.ResourceName = Guid.NewGuid().ToString().ToLower() + ".jpg";
var resultPicture = await App.MobileService.InvokeApiAsync<DTO.PictureStorage, DTO.PictureStorage>("user/blobStorage", uploadImage);
uploadImage = resultPicture;
// If we have a returned SAS, then upload the blob.
if (!string.IsNullOrEmpty(uploadImage.SasQueryString))
{
// Get the URI generated that contains the SAS
// and extract the storage credentials.
StorageCredentials cred = new StorageCredentials(uploadImage.SasQueryString);
var imageUri = new Uri(uploadImage.ImageUri);
// Instantiate a Blob store container based on the info in the returned item.
CloudBlobContainer container = new CloudBlobContainer(
new Uri(string.Format("http://{0}/{1}",
imageUri.Host.ToLower(), uploadImage.ContainerName.ToLower())), cred);
// Upload the new image as a BLOB from the stream.
CloudBlockBlob blobFromSASCredential =
container.GetBlockBlobReference(uploadImage.ResourceName);
await blobFromSASCredential.UploadFromStreamAsync(stream); //The exception is thrown here
// When you request an SAS at the container-level instead of the blob-level,
// you are able to upload multiple streams using the same container credentials.
stream = null;
}
On the server I have this code:
string storageAccountName;
string storageAccountKey;
// Try to get the Azure storage account token from app settings.
if (!(Services.Settings.TryGetValue("STORAGE_ACCOUNT_NAME", out storageAccountName) |
Services.Settings.TryGetValue("STORAGE_ACCOUNT_ACCESS_KEY", out storageAccountKey)))
{
Services.Log.Error("Could not retrieve storage account settings.");
}
// Set the URI for the Blob Storage service.
Uri blobEndpoint = new Uri(string.Format("https://{0}.blob.core.windows.net", storageAccountName));
// Create the BLOB service client.
CloudBlobClient blobClient = new CloudBlobClient(blobEndpoint,
new StorageCredentials(storageAccountName, storageAccountKey));
if (item.ContainerName != null)
{
// Set the BLOB store container name on the item, which must be lowercase.
item.ContainerName = item.ContainerName.ToLower();
// Create a container, if it doesn't already exist.
CloudBlobContainer container = blobClient.GetContainerReference(item.ContainerName);
try
{
await container.DeleteIfExistsAsync();
Services.Log.Info("Deleted.");
}
catch
{
Services.Log.Info("Could not DeleteIfExist.");
}
await container.CreateIfNotExistsAsync();
// Create a shared access permission policy.
BlobContainerPermissions containerPermissions = new BlobContainerPermissions();
// Enable anonymous read access to BLOBs.
containerPermissions.PublicAccess = BlobContainerPublicAccessType.Blob;
container.SetPermissions(containerPermissions);
// Define a policy that gives write access to the container for 5 minutes.
SharedAccessBlobPolicy sasPolicy = new SharedAccessBlobPolicy()
{
SharedAccessStartTime = DateTime.UtcNow,
SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(5),
Permissions = SharedAccessBlobPermissions.Write
};
// Get the SAS as a string.
item.SasQueryString = container.GetSharedAccessSignature(sasPolicy);
// Set the URL used to store the image.
item.ImageUri = string.Format("{0}{1}/{2}", blobEndpoint.ToString(),
item.ContainerName, item.ResourceName);
}
// Complete the insert operation.
user.ContainerName = item.ContainerName;
user.ResourceName = item.ResourceName;
user.SasQueryString = item.SasQueryString;
user.ImageUri = item.ImageUri;
user.Update = DateTime.UtcNow.AddMinutes(5);
db.SaveChanges();
I introduced the delete await based on this answer: https://stackoverflow.com/a/3221638/2076775
Hope somebody can tell me what stupid mistake I am making because I cannot find it. And unfortunately I cannot get fiddler to work (company policy and proxy settings :S).
The aim of the code is to upload an image, and it should be possible to do it again and again to the same address if the user changes the image.
CloudBlockBlob blobFromSASCredential = container.GetBlockBlobReference(uploadImage.ResourceName); await blobFromSASCredential.UploadFromStreamAsync(stream);
I have marked it in the code now – JTIM