获取Azure Blob上的实际上载进度

时间:2014-01-20 16:23:41

标签: c# file-upload azure upload progress

我知道已经提出过这个问题,但标记的解决方案并不正确。通常,本文标记为解决方案:http://blogs.msdn.com/b/kwill/archive/2013/03/06/asynchronous-parallel-block-blob-transfers-with-progress-change-notification-2-0.aspx

它可以工作并提供实际进度,但不是实时进度(在某些情况下,它会提供完全错误的值)。让我解释一下:

它提供了本地读取缓冲区的进度,因此当我上传内容时,我的第一个“上传的值”是读取缓冲区的总大小。在我的情况下,这个缓冲区是4mb,所以每个小于4mb的文件结果在0秒内完成进度条,但它需要真正的上传时间才能完成。

此外,如果您尝试在上传开始之前终止连接,则会将第一个缓冲区大小作为实际进度,因此对于我的1mb文件,我在断开连接时获得100%的进展

我发现另一篇文章有​​另一个解决方案,它每次完成单个块上传时都会从azure读取http响应,但我需要我的块 4mb (因为单个文件的最大块数)是50.000)并且即使块尺寸较小也不是完美的解决方案。

第一篇文章覆盖了流类并创建了一个ProgressStream类,其中每次读取完成时都会触发ProgressChanged事件,有一些方法可以知道实际在触发ProgressChanged时上传的字节数?

2 个答案:

答案 0 :(得分:2)

您可以使用类似于http://blogs.msdn.com/b/kwill/archive/2011/05/30/asynchronous-parallel-block-blob-transfers-with-progress-change-notification.aspx的代码(您引用的博客文章的1.0版)来执行此操作,但不是调用m_Blob.PutBlock而是使用HTTPWebRequest对象上传块并使用progress事件来自HTTPWebRequest类。这会引入更多代码复杂性,您必须添加一些额外的错误处理。

另一种方法是从GitHub下载Storage Client Library源代码,并修改块上传方法以跟踪和报告进度。您将面临的挑战是,如果您计划及时了解最新的修补程序,则必须对每个新版本的SCL进行相同的更改。

答案 1 :(得分:0)

我必须承认我没有检查是否所有内容都符合您的要求,但这是我上传时带有进度指示的2美分。

public async Task UploadVideoFilesToBlobStorage(List<VideoUploadModel> videos, CancellationToken cancellationToken)
{
    var blobTransferClient = new BlobTransferClient();
    //register events
    blobTransferClient.TransferProgressChanged += BlobTransferClient_TransferProgressChanged;
    //files
    _videoCount = _videoCountLeft = videos.Count;
    foreach (var video in videos)
    {
        var blobUri = new Uri(video.SasLocator);
        //create the sasCredentials
        var sasCredentials = new StorageCredentials(blobUri.Query);
        //get the URL without sasCredentials, so only path and filename.
        var blobUriBaseFile = new Uri(blobUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path,
            UriFormat.UriEscaped));
        //get the URL without filename (needed for BlobTransferClient (seems to me like a issue)
        var blobUriBase = new Uri(blobUriBaseFile.AbsoluteUri.Replace("/"+video.Filename, ""));

        var blobClient = new CloudBlobClient(blobUriBaseFile, sasCredentials);
        //upload using stream, other overload of UploadBlob forces to put online filename of local filename
        using (FileStream fs = new FileStream(video.FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        {
            await blobTransferClient.UploadBlob(blobUriBase, video.Filename, fs, null, cancellationToken, blobClient, 
                new NoRetry(), "video/x-msvideo");
        }
        _videoCountLeft -= 1;
    }

    blobTransferClient.TransferProgressChanged -= BlobTransferClient_TransferProgressChanged;
}

private void BlobTransferClient_TransferProgressChanged(object sender, BlobTransferProgressChangedEventArgs e)
{
    Console.WriteLine("progress, seconds remaining:" + e.TimeRemaining.Seconds);
    double bytesTransfered = e.BytesTransferred;
    double bytesTotal = e.TotalBytesToTransfer;
    double thisProcent = bytesTransfered / bytesTotal;
    double procent = thisProcent;
    //devide by video amount
    int videosUploaded = _videoCount - _videoCountLeft;
    if (_videoCountLeft > 0)
    {
        procent = (thisProcent + videosUploaded) / _videoCount;
    }

    procent = procent * 100;//to real %
    UploadProgressChangedEvent?.Invoke((int)procent, videosUploaded, _videoCount);
}

实际上Microsoft.WindowsAzure.MediaServices.Client.BlobTransferClient应该可以进行并发上传,但没有上传多个方法,但它有NumberOfConcurrentTransfersParallelTransferThreadCount的属性,不知道如何使用它。

BlobTransferClient中存在一个错误,当使用localFile参数上传时,它将使用该文件的文件名,而我在SaSLocator中授予特定文件名的权限。

此示例显示如何从客户端(而不是在服务器上)上传,因此我们通常不需要任何CloudMediaContext。关于SasLocators的一切都可以找到here