【问题标题】:Getting an error when uploading a file to Azure Storage将文件上传到 Azure 存储时出错
【发布时间】:2018-11-10 01:14:52
【问题描述】:

我正在将网站从标准 ASP.NET 网站转换为使用 Azure。该网站之前已获取管理员用户上传的 Excel 文件并将其保存在文件系统中。作为迁移的一部分,我将此文件保存到 Azure 存储。通过 Azure SDK 对我的本地存储运行时,它运行良好。 (我正在使用 1.3 版本,因为我不想在开发过程中升级。)

但是,当我将代码指向 Azure 存储本身时,该过程通常会失败。我得到的错误是: 发生 System.IO.IOException

  Message=Unable to read data from the transport connection: The connection was closed.
  Source=Microsoft.WindowsAzure.StorageClient
  StackTrace:
       at Microsoft.WindowsAzure.StorageClient.Tasks.Task`1.get_Result()
       at Microsoft.WindowsAzure.StorageClient.Tasks.Task`1.ExecuteAndWait()
       at Microsoft.WindowsAzure.StorageClient.CloudBlob.UploadFromStream(Stream source, BlobRequestOptions options)
       at Framework.Common.AzureBlobInteraction.UploadToBlob(Stream stream, String BlobContainerName, String fileName, String contentType) in C:\Development\RateSolution2010\Framework.Common\AzureBlobInteraction.cs:line 95
  InnerException: 

代码如下:

public void UploadToBlob(Stream stream, string BlobContainerName, string fileName,
        string contentType)
    {
        // Setup the connection to Windows Azure Storage
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(GetConnStr());

        DiagnosticMonitorConfiguration dmc = DiagnosticMonitor.GetDefaultInitialConfiguration();
        dmc.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
        dmc.Logs.ScheduledTransferLogLevelFilter = LogLevel.Verbose;
        DiagnosticMonitor.Start(storageAccount, dmc);      
        CloudBlobClient BlobClient = null;
        CloudBlobContainer BlobContainer = null;
        BlobClient = storageAccount.CreateCloudBlobClient();

        // For large file copies you need to set up a custom timeout period
        // and using parallel settings appears to spread the copy across multiple threads
        // if you have big bandwidth you can increase the thread number below
        // because Azure accepts blobs broken into blocks in any order of arrival.
        BlobClient.Timeout = new System.TimeSpan(1, 0, 0);
        Role serviceRole = RoleEnvironment.Roles.Where(s => s.Value.Name == "OnlineRates.Web").First().Value;
        BlobClient.ParallelOperationThreadCount = serviceRole.Instances.Count;  

        // Get and create the container
        BlobContainer = BlobClient.GetContainerReference(BlobContainerName);
        BlobContainer.CreateIfNotExist();

        //delete prior version if one exists
        BlobRequestOptions options = new BlobRequestOptions();
        options.DeleteSnapshotsOption = DeleteSnapshotsOption.None;
        CloudBlob blobToDelete = BlobContainer.GetBlobReference(fileName);
        Trace.WriteLine("Blob " + fileName + " deleted to be replaced by newer version.");
        blobToDelete.DeleteIfExists(options);

        //set stream to starting position
        stream.Position = 0;
        long totalBytes = 0;
        //Open the stream and read it back.
        using (stream)
        {
            // Create the Blob and upload the file
            CloudBlockBlob blob = BlobContainer.GetBlockBlobReference(fileName);
            try
            {
                BlobClient.ResponseReceived += new EventHandler<ResponseReceivedEventArgs>((obj, responseReceivedEventArgs)
                =>
                {
                    if (responseReceivedEventArgs.RequestUri.ToString().Contains("comp=block&blockid"))
                    {
                        totalBytes += Int64.Parse(responseReceivedEventArgs.RequestHeaders["Content-Length"]);
                    }
                });                 
                blob.UploadFromStream(stream);
                // Set the metadata into the blob
                blob.Metadata["FileName"] = fileName;
                blob.SetMetadata();
                // Set the properties
                blob.Properties.ContentType = contentType;
                blob.SetProperties();
            }
            catch (Exception exc)
            {
                Logging.ExceptionLogger.LogEx(exc);
            }
         }
     }

我已尝试对代码进行多种不同的更改:在替换之前删除 blob(尽管问题也存在于新 blob 上)、设置容器权限、不设置权限等。

【问题讨论】:

  • 我会对代码进行一些更改,但它们不会导致您看到的问题。你真的需要totalBytes吗?您是否尝试过没有收到响应的事件处理程序?
  • 事件处理程序被抛出只是为了看看传输是否有任何事情发生。它似乎对性能没有影响。
  • 另外,我应该问:这段代码在一个单独的项目中运行,该项目作为 DLL 编译到 Web 角色中。 (Web 角色只是一个 Web 解决方案项目。)这有什么不同吗?代码是否需要实际存在于角色本身中? (我对此表示怀疑,因为它偶尔会起作用,但我想我应该问一下。)
  • 您能否展示一下您的 Azure Blob 连接是如何配置的?你确定在项目文件中配置好 http/https 设置了吗? GetConnStr() 返回什么? - 但请不要发布您的实际访问密钥 :)
  • 另外,BlobClient.ParallelOperationThreadCount = serviceRole.Instances.Count; 是干什么用的?

标签: azure azure-storage


【解决方案1】:

您的代码看起来应该可以工作,但它具有许多并非严格要求的额外功能。我会把它减少到绝对最低限度,然后从那里开始。这真的只是一种直觉,但我认为这可能是让你悲伤的使用语句。这个enture函数可以写成(假设容器已经存在):

public void UploadToBlob(Stream stream, string BlobContainerName, string fileName,
                string contentType)
            {
                // Setup the connection to Windows Azure Storage
                CloudStorageAccount storageAccount = CloudStorageAccount.Parse(GetConnStr());
                CloudBlobClient BlobClient = storageAccount.CreateCloudBlobClient();
                CloudBlobContainer BlobContainer = BlobClient.GetContainerReference(BlobContainerName);
                CloudBlockBlob blob = BlobContainer.GetBlockBlobReference(fileName);
                stream.Position = 0;
                blob.UploadFromStream(stream);
            }

关于我删除的内容的注释:

  • 您应该只在应用程序启动时设置一次诊断,而不是每次调用方法时。通常在 RoleEntryPoint.OnStart()
  • 如果您有更多实例,我不确定您为什么要尝试将ParallelOperationThreadCount 设置得更高。这两件事似乎无关。
  • 每次向其中保存内容时检查容器/表是否存在并不是一种好方法。通常在您的应用程序启动时进行一次检查,或者在网站外部有一个进程以确保所有必需的容器/表/队列都存在。当然,如果您尝试动态创建容器,则并非如此。

【讨论】:

    【解决方案2】:

    问题出在我笔记本电脑上的防火墙设置上。这是我最初在家中设置的个人笔记本电脑,因此没有为公司环境设置防火墙规则,导致上传和下载性能下降。

    【讨论】:

      猜你喜欢
      • 2021-11-30
      • 2020-11-17
      • 2014-08-08
      • 2018-02-16
      • 1970-01-01
      • 2017-01-24
      • 2017-08-19
      • 1970-01-01
      • 2017-04-11
      相关资源
      最近更新 更多