【问题标题】:Azure Cloud storage SDK UploadFromStreamAsync not workingAzure 云存储 SDK UploadFromStreamAsync 不起作用
【发布时间】:2018-12-16 10:13:47
【问题描述】:

我正在尝试将文件上传到 .Net Core 2.1 中的 Azure blob 存储。下面是我的代码。

IFormFileCollection files = formCollection.Files;

foreach (var file in files)
{
    if (file.Length > 0)
    {
        _azureCloudStorage.UploadContent(cloudBlobContainer, file.OpenReadStream(), file.FileName);
    }
}

UploadContent 实现-

public async void UploadContent(CloudBlobContainer containerReference, Stream contentStream, string blobName)
{
    try
    {
        using (contentStream)
        {
            var blockBlobRef = containerReference.GetBlockBlobReference(blobName);
            //await containerReference.SetPermissionsAsync(new BlobContainerPermissions
            //{
            //    PublicAccess = BlobContainerPublicAccessType.Blob
            //});
            await blockBlobRef.UploadFromStreamAsync(contentStream);
        }
    }
    catch(Exception ex)
    {
        //Error here
    }
}

代码执行时出现以下错误-

{System.ObjectDisposedException:无法访问已关闭的文件。在 System.IO.FileStream.get_Position() 在 Microsoft.AspNetCore.WebUtilities.FileBufferingReadStream.get_Position() 在 Microsoft.AspNetCore.Http.Internal.ReferenceReadStream.VerifyPosition() 在 Microsoft.AspNetCore.Http.Internal.ReferenceReadStream.ReadAsync(字节[] 缓冲区,Int32 偏移量,Int32 计数,CancellationToken 取消令牌)在 Microsoft.WindowsAzure.Storage.Core.Util.StreamExtensions.WriteToAsync[T](流 stream, Stream toStream, IBufferManager bufferManager, Nullable1 copyLength, Nullable1 maxLength, Boolean calculateMd5, ExecutionState1 executionState, StreamDescriptor streamCopyState, CancellationToken token) in C:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\Common\Core\Util\StreamExtensions.cs:line 301 at Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadFromStreamAsyncHelper(Stream source, Nullable1 长度,AccessCondition accessCondition, BlobRequestOptions 选项,OperationContext operationContext, IProgress1 progressHandler, CancellationToken cancellationToken) in C:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\WindowsRuntime\Blob\CloudBlockBlob.cs:line 352 at Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadFromStreamAsyncHelper(Stream source, Nullable1 长度,AccessCondition accessCondition, BlobRequestOptions 选项,OperationContext operationContext, C:\Program Files 中的 CancellationToken cancelToken) (x86)\Jenkins\workspace\release_dotnet_master\Lib\WindowsRuntime\Blob\CloudBlockBlob.cs:line 290 在 Common.AzureCloudStorage.UploadContent(CloudBlobContainer containerReference, Stream contentStream, String blobName)

对我有用的替代解决方案: adding to azure blob storage with stream

请问有什么帮助吗?如果我可以提供更多详细信息,请告诉我。

【问题讨论】:

  • 等待从StreamAsync上传?
  • @OlaEkdahl 我尝试使用 awaiter-blockBlobRef.UploadFromStreamAsync(contentStream).GetAwaiter(),但也没有用。也试过await,没用。
  • 我在处理大文件时遇到了类似的问题,我不得不增加 maxRequestLength。也许这里的东西会起作用,stackoverflow.com/questions/38698350/…
  • @OlaEkdahl 这个解决方案适合我-stackoverflow.com/questions/47296020/…

标签: c# azure asp.net-core azure-blob-storage


【解决方案1】:

我的解决方案是等到任务完成后再继续,例如

    private async void SaveAsync(IFormFile file)
    {
        CloudBlockBlob blob = this.blobContainer.GetBlockBlobReference(file.FileName);
        var task = blob.UploadFromStreamAsync(file.OpenReadStream(), file.Length);

        while (task.IsCompleted == false) {
            Thread.Sleep(1000);
        }

    }

也许传递长度也有帮助?

【讨论】:

  • 为什么传递长度也会有所不同?
  • 如果不检查 CloudBlockBlob 的源代码,这很难说,但我猜测它有助于 blob 知道何时完成读取流,因为它会知道它需要多少字节阅读..
【解决方案2】:

我的解决方案是包含文件长度并将位置设置为 0。

MemoryStream outStr = new MemoryStream();
CloudBlockBlob myBlob = container.GetBlockBlobReference(name);
outStr.Position = 0;
await myBlob.UploadFromStreamAsync(outStr, outStr.Length);

【讨论】:

  • 只设置 .Position = 0 对我有用,谢谢!
【解决方案3】:

同样的问题,几年后(WindowsAzure.Storage 版本 3.0.3.0,targetFramework net45)。
同步 UploadFromStream 有效,UploadFromStreamAsync 无效。 我会投票赞成怀疑 Azure SDK 不完善异步版本,而不是 sdk 使用不足。而且,我也是一位相当有经验的开发人员 - 经验丰富,不会时不时地绊倒微软声明的一项功能,但在仔细审查时却无法使用。
其他异步方法也一样(例如 SetPropertiesAsync)。我一直在调试我的方法(如下),并且在每个 *Async 方法之后都丢失了断点 - 这就是我想出的方法。出于好奇,将 UploadFromStreamAsync => UploadFromStream,然后将 SetPropertiesAsync 更改为 SetProperties

    public async Task StoreItem(string filename, MemoryStream content, string contentType, ICloudBlob cloudBlob)
{
    cloudBlob.UploadFromStream(content); //this line works
    //await cloudBlob.UploadFromStreamAsync(content); //doesn't work
    cloudBlob.Properties.ContentType = contentType;
    cloudBlob.SetProperties();
    //await cloudBlob.SetPropertiesAsync(); //doesn't work either
}

【讨论】:

  • 也许文件超出范围并被垃圾收集,并在异步方法执行之前关闭文件?这似乎符合史蒂夫史密斯的评论(就在下面)。我不是异步方法的对象生命周期范围方面的专家。
【解决方案4】:

将位置设置为 0 并将流长度传递给 UploadFromStreamAsync() 解决了我的问题(文件没有上传,即使容器已经存在)。

using (var stream = file.OpenReadStream())
{
    var fileBlob = container.GetBlockBlobReference(fileName);
    stream.Position = 0;
    fileBlob.UploadFromStreamAsync(stream, stream.Length);
}

【讨论】:

    【解决方案5】:

    我已经测试了你的方法UploadContent,效果很好。

    我猜你的问题可能是你得到的文件集合。

    这是我的代码供您参考:

    using ConsoleAppCore.DAL;
    using Microsoft.Azure.Storage;
    using Microsoft.Azure.Storage.Blob;
    using System;
    using System.IO;
    
    namespace ConsoleAppCore
    {
        class Program
        {
            static void Main(string[] args)
            {
                Run();
                Console.WriteLine("Success");
                Console.ReadLine();
            }
    
            public static void Run()
            {
                CloudStorageAccount storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=xxxxx;AccountKey=O7xB6ebGq8e86XQSy2vkvSi/x/exxxxxxxxxxkly1DsQPYY5dF2JrAVHtBozbJo29ZrrGJA==;BlobEndpoint=https://xxxx.blob.core.windows.net/;QueueEndpoint=https://xxxx.queue.core.windows.net/;TableEndpoint=https://xxxx.table.core.windows.net/;FileEndpoint=https://xxxx.file.core.windows.net/;");
    
                CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
                CloudBlobContainer container = cloudBlobClient.GetContainerReference("containertest");
    
                container.CreateIfNotExists();
                DirectoryInfo dir = new DirectoryInfo("E://Test");
    
                foreach (FileInfo file in dir.GetFiles())
                {
    
                    BlobStorage.UploadContent(container, file.OpenRead(), file.Name);
    
                }
            }
    
    
        }
    }
    

    还有我的BlobStorage 类中的UploadContent 方法:

    using Microsoft.Azure.Storage.Blob;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    
    namespace ConsoleAppCore.DAL
    {
        public class BlobStorage
        {
            public static async void UploadContent(CloudBlobContainer containerReference, Stream contentStream, string blobName)
            {
                try
                {
                    using (contentStream)
                    {
    
                        var blockBlobRef = containerReference.GetBlockBlobReference(blobName);
                        //await containerReference.SetPermissionsAsync(new BlobContainerPermissions
                        //{
                        //    PublicAccess = BlobContainerPublicAccessType.Blob
                        //});
                        await blockBlobRef.UploadFromStreamAsync(contentStream);
                    }
                }
                catch (Exception ex)
                {
                    //Error here
                }
            }
        }
    }
    

    【讨论】:

    • 您使用的是FileInfo,而我使用的是IFormFile。可能就是这个原因。我已经尝试过类似的代码,并且可以从本地上传文件。我只是面临IFormFile对象形式提交的文件的问题。
    猜你喜欢
    • 2019-10-02
    • 2020-01-20
    • 2023-01-23
    • 1970-01-01
    • 2021-10-28
    • 2014-03-29
    • 2014-04-24
    • 1970-01-01
    • 2019-11-17
    相关资源
    最近更新 更多