c# - 使用 SasLocator 上传到 Azure 媒体服务/blob 存储不显示上传的文件

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

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

我正在尝试做以下组合:

  • 这个旧文档:3 - Uploading Video into Microsoft Azure Media Services
  • 和这个相对较新的文档:Upload multiple files with Media Services .NET SDK .

  • 第一个展示了我的场景的完美示例,但第二个展示了如何使用 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);
    }
    

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

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

    上传:

    uploading of asset

    Assets 已创建但没有文件:

    media services

    存储也不显示任何文件:

    blob containers

    存储确实显示成功上传:

    statistics

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

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

    更新 1

    使用 CloudBlockBlob 上传时它确实再次上传,并显示在我的 Assets 中的存储帐户中,但是当我进入 azure 中的媒体服务并单击特定 Assets 时,它不显示任何文件。

    所以代码:
    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 中手动上传 Assets 。所以点击 Assets 菜单中的“上传”,然后对其进行编码。这一切都很好。

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

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

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

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

    最佳答案

    最终结果证明我需要指定 基本网址 UploadBlob方法,因此没有 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应该能够进行并发上传,但没有上传多个的方法,但它具有 NumberOfConcurrentTransfers 的属性和 ParallelTransferThreadCount ,不知道怎么用。

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

    关于c# - 使用 SasLocator 上传到 Azure 媒体服务/blob 存储不显示上传的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50626180/

    相关文章:

    c# - "Missing map from System.Char to System.String"AutoMapper 错误

    c# - MVC 4 表单例份验证不适用于 [Authorize]

    azure - 无法使用Azure中的 secret 计算虚拟机部署服务

    azure - 用于在 Azure 存储中编辑 MS Word 文档的选项

    azure : VNet Integration || The gateway did not receive a response from 'Microsoft.Web'

    c# - linq 成员不支持 SQL 转换

    c# - 为 JSON 对象数组命名

    azure - 如何启动 azure 解除分配的虚拟机?

    副本的 Azure 容器应用程序单一主机名

    azure - Windows azure 带宽和 CDN 之间的关系