c# - 使用 SasLocator 上传到 Azure 媒体服务/blob 存储不显示上传的文件
问题描述
所以我想将视频从客户端桌面应用程序上传到 Azure 媒体服务(当然使用 Azure 存储)。
我正在尝试做以下组合:
- 这个旧文档:3 - 将视频上传到 Microsoft Azure 媒体服务
- 和这个相对较新的文档: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);
}
我知道我可能没有正确地命名资产并使用进度指示器而不是等待,但当然我首先希望它在完成之前先工作。
我将 Azure 媒体服务配置为“使用服务主体连接到媒体服务 API”,在那里我创建了一个新的 Azure AD 应用程序并为此生成了密钥,就像这个文档页面一样。我不太确定这到底是如何工作的,在 Azure AD 和 Azure AD 应用程序中几乎没有经验(指导?)。
上传:
资产已创建但没有文件:
存储也不显示任何文件:
存储确实显示成功上传:
我不能完全遵循Upload multiple files with Media Services .NET SDK文档的原因是因为它使用_context
(即Microsoft.WindowsAzure.MediaServices.Client.CloudMediaContext
),_context
我可以使用服务器端但不能使用客户端,因为它需要 TenantDomain、RESTAPI 端点、ClientId 和客户机密。
我想通过 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 函数(已经计划这样做)来处理资产创建、文件上传到资产、编码和发布。这已通过遵循本教程完成:Visual Studio 的 Azure Functions 工具,然后实现使用媒体服务 .NET SDK 上传多个文件中说明的代码。
所以这个“有效”但还不完美,我的客户端 WPF 应用程序中仍然没有我的进度指示器,Azure 函数需要很长时间才能完成,因为我们基本上在它之后再次将文件“上传”到资产已在 Azure 存储中。我宁愿使用一种方法从一个容器复制到一个资产容器。
我来到这一点是因为 Azure 函数需要一个固定的给定容器名称,因为资产在存储帐户中创建自己的容器,因此您不能在这些容器上触发 Azure 函数。因此,要使用 Azure Functions,我似乎真的必须将它上传到一个固定的容器名称,然后再完成其余的工作。
问题仍然存在:为什么通过 将视频文件上传到 Azure 存储BlobTransferClient
不起作用?如果它可以工作,我如何触发基于多个容器的 Azure 功能。像asset-{name}/{name}.avi 这样的“路径”是首选。
解决方案
最终结果是我需要在方法中指定基本 URLUploadBlob
,因此没有文件名本身,它位于 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
应该能够进行并发上传,但没有上传多个的方法,但它具有 and 的属性NumberOfConcurrentTransfers
,ParallelTransferThreadCount
不知道如何使用它。
我没有检查这是否现在也适用于资产,因为我现在为每个文件上传到 1 个单个容器,然后使用 Azure 函数处理到资产,主要是因为我无法在动态上触发 Azure 函数容器名称(每个资产创建自己的容器)。
推荐阅读
- c# - 使用正则表达式更改
文本 到文本 - vba - 无法使用 FSO 重命名文件(文件名称中有空格)
- r - ggplot:geom_text输出的文字不清晰,字字体很糟糕
- node.js - Reactjs 跨多个主机实时更新应用程序
- r - 在 R 组中并计算事件发生后的天数
- image - 使用 CNN 去噪图像中的图像尺寸
- flutter - *为什么* SizedBox 的宽度和高度没有任何影响?
- java - 如何模拟本地 OAuth2RestTemplate restTemplate?
- python - 在 python 子进程中捕获 logger.info 输出?
- mapstruct - 使用 MapStruct 将 JSON 转换为 Java Pojo