Исключение NotFound в Azure BlobStorage

Я знаю, что этот вопрос задавали много раз. Но я просто не могу заставить его работать надежно.

Я получаю это исключение:

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: 

Код, который я использую для загрузки на сервер:

 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;
        }

На сервере у меня есть этот код:

 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();

Я представил ожидание удаления на основе этого ответа: https://stackoverflow.com/a/3221638/2076775

Надеюсь, кто-нибудь скажет мне, какую глупую ошибку я совершаю, потому что не могу ее найти. И, к сожалению, я не могу заставить скрипач работать (политика компании и настройки прокси: S).

Цель кода — загрузить изображение, и должна быть возможность делать это снова и снова по одному и тому же адресу, если пользователь меняет изображение.


person JTIM    schedule 26.02.2015    source источник
comment
Какая операция возвращает 404?   -  person Greg D    schedule 27.02.2015
comment
Извините, нужно было указать: CloudBlockBlob blobFromSASCredential = container.GetBlockBlobReference(uploadImage.ResourceName); await blobFromSASCredential.UploadFromStreamAsync(stream); Сейчас я отметил это в коде   -  person JTIM    schedule 27.02.2015


Ответы (1)


Код вашего сервера использует текущее время в качестве времени запуска SAS, что может вызвать проблемы с проверкой подлинности из-за расхождения часов. Другими словами, если текущее время службы BLOB-объектов отстает от текущего времени вашего сервера, токен SAS в этот момент недействителен. Если у вас нет жесткого ограничения на время запуска, рекомендуется полностью его опустить.

person Serdar Ozler    schedule 26.02.2015
comment
Хорошо, у меня есть время начала, когда клиент хочет его создать/обновить. Я думал, что, используя utc, вы ограничите и закроете, чтобы устранить проблему? Итак, вы бы удалили эти строки SharedAccessStartTime = DateTime.UtcNow, SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(5)? - person JTIM; 27.02.2015
comment
Вы должны удалить только время начала, так как оно не имеет большого значения, когда оно установлено сейчас. - person Serdar Ozler; 28.02.2015
comment
Хорошо, я попробую это позже, когда буду за ПК. Это единственная проблема? Если да, то не следует ли упоминать об этом в руководствах по MSDN? Спасибо за ваше время. - person JTIM; 28.02.2015
comment
Я проверил время, и оно было на несколько часов позже. так что спасибо! - person JTIM; 28.02.2015