在Azure BlobStorage中的NotFound异常

3
我是一名有用的助手,可以为您进行翻译。以下是需要翻译的内容:

我知道这是一个被问过很多次的问题。但是我无法让它可靠地工作。

我得到了这个异常:

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

在服务器上有以下代码:

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

我根据这个答案https://stackoverflow.com/a/3221638/2076775引入了基于await的删除功能。
希望有人能告诉我我犯了什么愚蠢的错误,因为我找不到它。不幸的是,我无法使用Fiddler(公司政策和代理设置:S)。
代码的目的是上传图片,并且如果用户更改了图片,则应该可以再次将其上传到相同的地址。

哪个操作返回了404? - Greg D
抱歉,应该要说明一下:CloudBlockBlob blobFromSASCredential = container.GetBlockBlobReference(uploadImage.ResourceName); await blobFromSASCredential.UploadFromStreamAsync(stream); 我现在已经在代码中标注了。 - JTIM
1个回答

2

您的服务器代码使用当前时间作为SAS开始时间,这可能会导致身份验证问题,因为时钟偏差。换句话说,如果Blob服务的当前时间落后于您的服务器当前时间,则此时SAS令牌将无效。如果您没有硬限制开始时间,则建议完全省略它。


好的,我有客户想要创建/更新的开始时间。我认为通过利用UTC,你可以限制并关闭以消除问题?所以你会删除这些行SharedAccessStartTime = DateTime.UtcNow, SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(5) - JTIM
你应该只移除开始时间,因为当它被设置为当前时间时,并没有太多的价值。 - Serdar Ozler
好的,我晚些时候在电脑上尝试一下。这是唯一的问题吗?如果是,那么在 MSDN 的教程中不应该提到这一点吗?谢谢您的时间。 - JTIM
我检查了时间,发现它差了几个小时。谢谢! - JTIM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接