【问题标题】:Upload to Azure Media Services / blob storage with SasLocator not showing uploaded file使用 SasLocator 上传到 Azure 媒体服务/blob 存储不显示上传的文件
【发布时间】:2018-11-10 13:52:06
【问题描述】:

所以我想将视频从客户端桌面应用程序上传到 Azure 媒体服务(当然使用 Azure 存储)。

我正在尝试做以下组合:

第一个展示了我的场景的完美示例,但第二个展示了如何使用BlobTransferClient 上传多个文件并具有“进度”指示器。

问题:它似乎可以上传,上传后我没有收到任何错误,但 Azure 门户/存储帐户中没有显示任何内容。 似乎上传是因为任务耗时较长,任务管理器显示 wifi 上传进度,Azure 存储显示正在发出(成功)请求。

所以,在服务器端,我临时创建了一个 SasLocator:

public async Task<VideoUploadModel> GetSasLocator(string filename)
{

    var assetName = filename + DateTime.UtcNow;

    IAsset asset = await _context.Assets.CreateAsync(assetName, AssetCreationOptions.None, CancellationToken.None);

    IAccessPolicy accessPolicy = _context.AccessPolicies.Create(assetName, TimeSpan.FromMinutes(10),
        AccessPermissions.Write);

    var locator = _context.Locators.CreateLocator(LocatorType.Sas, asset, accessPolicy);

    var blobUri = new UriBuilder(locator.Path);
    blobUri.Path += "/" + filename;

    var model = new VideoUploadModel()
    {
        Filename = filename,
        AssetName = assetName,
        SasLocator = blobUri.Uri.AbsoluteUri,
        AssetId = asset.Id
    };
    return model;
}

和客户端,我尝试上传:

public async Task UploadVideoFileToBlobStorage(string[] files, string sasLocator, CancellationToken cancellationToken)
{
    var blobUri = new Uri(sasLocator);
    var sasCredentials = new StorageCredentials(blobUri.Query);

    //var blob = new CloudBlockBlob(new Uri(blobUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped)), sasCredentials);
    var blobClient = new CloudBlobClient(new Uri(blobUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped)), sasCredentials);
    var blobTransferClient = new BlobTransferClient(TimeSpan.FromMinutes(1))
    {
        NumberOfConcurrentTransfers = 2,
        ParallelTransferThreadCount = 2
    };
    //register events
    blobTransferClient.TransferProgressChanged += BlobTransferClient_TransferProgressChanged;
    //files
    var uploadTasks = new List<Task>();
    foreach (var filePath in files)
    {
        await blobTransferClient.UploadBlob(blobUri, filePath, new FileEncryption(), cancellationToken, blobClient, new NoRetry());
    }



    //StorageFile storageFile = null;

    //if (string.IsNullOrEmpty(file.FutureAccessToken))
    //{
    //    storageFile = await StorageFile.GetFileFromPathAsync(file.Path).AsTask(cancellationToken);
    //}
    //else
    //{
    //    storageFile = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(file.FutureAccessToken).AsTask(cancellationToken);
    //}
    //cancellationToken.ThrowIfCancellationRequested();
    //await blob.UploadFromFileAsync(storageFile);
}

我知道我可能没有正确地命名资产并使用进度指示器而不是等待,但当然我首先希望它在完成之前先工作。

我将 Azure 媒体服务配置为“使用服务主体连接到媒体服务 API”,我在其中创建了一个新的 Azure AD 应用并为此生成了密钥,例如 this documentation page。我不确定这到底是如何工作的,对 Azure AD 和 Azure AD 应用程序几乎没有经验(指导?)。

上传中:

资产已创建但没有文件:

存储也不显示任何文件:

存储显示上传成功:

我不能完全遵循Upload multiple files with Media Services .NET SDK 文档的原因是因为它使用_context(即Microsoft.WindowsAzure.MediaServices.Client.CloudMediaContext),_context 我可以使用服务器端但不能使用客户端,因为它需要TentantDomain ,RESTAPI Endpoint、ClientId 和 Client Secret。

我猜想通过 SaSLocator 上传是正确的方式 (?)。

更新 1

使用CloudBlockBlob 上传时,它会再次上传,并显示在我的存储帐户中的资产中,但是当我在 azure 中访问媒体服务并单击特定资产时,它不会显示任何文件。

所以代码:

var blob = new CloudBlockBlob(new Uri(blobUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped)), sasCredentials);
//files
var uploadTasks = new List<Task>();
foreach (var filePath in files)
{
    await blob.UploadFromFileAsync(filePath, CancellationToken.None);
}

我还尝试在 Azure 中手动上传资产。所以点击资产菜单中的“上传”,然后对其进行编码。这一切都很好。

更新 2:

深入挖掘后,我想出了以下尚未经过生产验证的方法,使其目前可以正常工作:

1. 直接从存储中获取共享访问签名并将其上传到那里:

public static async Task<string> GetMediaSasLocator(string filename)
{
    CloudBlobContainer cont = await GetMediaContainerAsync();
    SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy()
    {
        SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddMinutes(60),
        Permissions = SharedAccessBlobPermissions.Write,
        SharedAccessStartTime = DateTimeOffset.UtcNow.AddMinutes(-5)
    };
    await cont.FetchAttributesAsync();

    return cont.Uri.AbsoluteUri + "/" + filename + cont.GetSharedAccessSignature(policy);
}

有了这个 SaS,我可以上传,就像我在 UPDATE 1 中展示的那样,那里没有任何改变。

2. 创建一个处理资产创建、文件上传到资产、编码和发布的 Azure 函数(已经计划这样做)。 这已通过遵循本教程完成:Azure Functions Tools for Visual Studio,然后实现Upload multiple files with Media Services .NET SDK 中说明的代码。

所以这个“有效”但还不完美,我的客户端 WPF 应用程序中仍然没有进度指示器,Azure 函数需要很长时间才能完成,因为我们基本上将文件再次“上传”到已在 Azure 存储中之后的资产。我宁愿使用一种方法从一个容器复制到一个资产容器。

我来到这一点是因为 Azure 函数需要一个固定的给定容器名称,因为资产会在存储帐户中创建自己的容器,因此您无法在这些容器上触发 Azure 函数。因此,要使用 Azure Functions,看来我真的必须将其上传到一个固定的容器名称,然后再完成其余的工作。

问题仍然存在: 为什么通过 BlobTransferClient 将视频文件上传到 Azure 存储不起作用?如果它可以工作,我如何触发基于多个容器的 Azure 功能。像asset-{name}/{name}.avi 这样的“路径”是首选。

【问题讨论】:

    标签: c# azure azure-storage azure-mobile-services


    【解决方案1】:

    最终我发现我需要在 UploadBlob 方法中指定 基本 URL,因此没有 SasLocator URL 中的文件名本身,而只有容器名称。

    一旦我修复了这个问题,我还注意到它没有上传到我在 SasLocator 中提供的文件名,我生成了服务器端(它包括一个 customerID 前缀)。我必须使用其他方法重载之一来获取正确的文件名。

    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的属性,不知道怎么用。

    我没有检查这是否也适用于资产,因为我现在为每个文件上传到 1 个单个容器,然后使用 Azure 函数处理资产,主要是因为我无法触发 Azure 函数在动态容器名称上(每个资产创建自己的容器)。

    【讨论】:

      猜你喜欢
      • 2015-05-20
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 2018-10-29
      • 2022-01-18
      • 2017-01-24
      • 2017-08-19
      • 1970-01-01
      相关资源
      最近更新 更多