/// <summary> /// Copies asset data from source Azure Media Services instance to target using Azure Blob Copy /// </summary> /// <param name="sourceClient">Source Azure Media Services instance client</param> /// <param name="sourceConfig">Source Azure Media Services instance configuration</param> /// <param name="targetClient">Target Azure Media Services instance client</param> /// <param name="targetConfig">Target Azure Media Services instance configuration</param> /// <param name="provisioningRequest">Provisioning request data</param> /// <param name="logger">Logger to log data</param> /// <returns>Target asset</returns> private async Task <Asset> CopyAssetAsync(IAzureMediaServicesClient sourceClient, MediaServiceConfigurationModel sourceConfig, IAzureMediaServicesClient targetClient, MediaServiceConfigurationModel targetConfig, ProvisioningRequestModel provisioningRequest, ILogger logger) { logger.LogInformation($"AssetDataProvisioningService::CopyAssetAsync started: provisioningRequest={LogHelper.FormatObjectForLog(provisioningRequest)} sourceInstanceName={sourceConfig.AccountName} targetInstanceName={targetConfig.AccountName}"); // Need to ensure that target asset exits var targetAsset = await targetClient.Assets.GetAsync(targetConfig.ResourceGroup, targetConfig.AccountName, provisioningRequest.ProcessedAssetName).ConfigureAwait(false); // if there is no target asset, need to provision one if (targetAsset == null) { // create new target asset targetAsset = await targetClient.Assets.CreateOrUpdateAsync(targetConfig.ResourceGroup, targetConfig.AccountName, provisioningRequest.ProcessedAssetName, new Asset()).ConfigureAwait(false); // need to reload asset to get Container value populated, otherwise Container is null after asset creation targetAsset = await targetClient.Assets.GetAsync(targetConfig.ResourceGroup, targetConfig.AccountName, provisioningRequest.ProcessedAssetName).ConfigureAwait(false); } // Get SAS token associated with source asset. SAS token is required to initiate StartCopyFromUri var sourceAssetContainerSas = await sourceClient.Assets.ListContainerSasAsync( sourceConfig.ResourceGroup, sourceConfig.AccountName, provisioningRequest.ProcessedAssetName, permissions : AssetContainerPermission.Read, expiryTime : DateTime.UtcNow.AddHours(1).ToUniversalTime()).ConfigureAwait(false); var sourceContainerSasUrl = new Uri(sourceAssetContainerSas.AssetContainerSasUrls.FirstOrDefault()); var sourceBlobClient = new BlobContainerClient(sourceContainerSasUrl); var copyTasks = new List <Task>(); // Get a list of all blobs to copy await foreach (var blobItem in sourceBlobClient.GetBlobsAsync()) { // All blobs can be copies in parallel copyTasks.Add(Task.Run(() => { // Get target blob var targetBlob = new BlobBaseClient(this.configService.MediaServiceInstanceStorageAccountConnectionStrings[targetConfig.AccountName], targetAsset.Container, blobItem.Name); // Get source blob var sourceBlob = sourceBlobClient.GetBlobClient(blobItem.Name); // Start copy operation, see more data about it https://docs.microsoft.com/en-us/dotnet/api/azure.storage.blobs.specialized.blobbaseclient.startcopyfromuriasync?view=azure-dotnet var copyOperation = targetBlob.StartCopyFromUri(sourceBlob.Uri); // Wait for copy to complete, since this is running on separate thread, no need to do async var copyResult = copyOperation.WaitForCompletionAsync().GetAwaiter().GetResult(); // Check copy operation status if (copyResult.GetRawResponse().Status != 200) { throw new Exception($"Copy operation failed, sourceAccount={sourceConfig.AccountName} targetAccount={targetConfig.AccountName} assetName={provisioningRequest.ProcessedAssetName} blobName={blobItem.Name} httpStatus={copyResult.GetRawResponse().Status}"); } })); } // Wait for all copy tasks to finish await Task.WhenAll(copyTasks).ConfigureAwait(false); logger.LogInformation($"AssetDataProvisioningService::CopyAssetAsync completed: provisioningRequest={LogHelper.FormatObjectForLog(provisioningRequest)} sourceInstanceName={sourceConfig.AccountName} targetInstanceName={targetConfig.AccountName} numberOfFiles={copyTasks.Count}"); return(targetAsset); }