使用Azure存储数据移动库阻止多个传输操作

时间:2016-11-17 17:54:46

标签: c# azure azure-storage

我刚开始使用代码类似于Azure Storage Data Movement Library (DML)public DML sample code。用例是(逐步)将本地目录同步到blob存储多次,同时目录中的某些文件会不时更新。

UploadDirectoryOptions options = new UploadDirectoryOptions
{
    SearchPattern = "*.*",
    Recursive = false,
    BlobType = BlobType.BlockBlob
};

// Register for transfer event.
DirectoryTransferContext context = new DirectoryTransferContext();

//only copy newer files - similar to AzCopy /XO /XN switches
//https://github.com/Azure/azure-storage-net-data-movement/issues/12
context.ShouldOverwriteCallback = (source, destination) =>
{
    var sourceFile = new FileInfo((string)source);
    var destBlob = destination as CloudBlob;
    return sourceFile.LastWriteTimeUtc > destBlob.Properties.LastModified;
};

// Start the upload
var transferStatus = await TransferManager.UploadDirectoryAsync(sourceDirPath, destDir, options, context);

目前,应用程序事件会触发传输操作。在短时间内尝试了几个事件,这引发了一个例外,如下所示。由于TransferManager是一个静态类,如何在我的应用程序中解决此要求并防止此类异常?

Microsoft.WindowsAzure.Storage.DataMovement.TransferException was unhandled
Message: An unhandled exception of type 'Microsoft.WindowsAzure.Storage.DataMovement.TransferException' occurred in mscorlib.dll
Additional information: A transfer operation with the same source and destination already exists.

3 个答案:

答案 0 :(得分:1)

我认为你的问题没有得到很好的优化。我觉得你和我有同样的问题。让我简单解释一下。你正在运行异步DirectoryUpload,当然在这种情况下"多个传输操作"将会。

在大多数情况下,如果跳过文件,则会发生此异常。这就是为什么你得到一个错误"具有相同源和目的地的传输操作已经存在。"在这种情况下,进度将跳过图像,您必须捕获如下所示。请参阅完整示例here

 DirectoryTransferContext context = new DirectoryTransferContext();
            context.FileTransferred += FileTransferredCallback;
            context.FileFailed +=FileFailedCallback;
            context.FileSkipped += FileSkippedCallback;

            context.SetAttributesCallback = (destination) =>
            {
                CloudBlob destBlob = destination as CloudBlob;
                destBlob.Properties.ContentType = "image/png";
            };

            context.ShouldTransferCallback = (source, destination) =>
            {
                // Can add more logic here to evaluate whether really need to transfer the target.
                return true;
            };

            // Start the upload
            var trasferStatus = await TransferManager.UploadDirectoryAsync(sourceDirPath, destDir, options, context);

private static void FileTransferredCallback(object sender, TransferEventArgs e)
    {
        Console.WriteLine("Transfer Succeeds. {0} -> {1}.", e.Source, e.Destination);
    }

    private static void FileFailedCallback(object sender, TransferEventArgs e)
    {
        Console.WriteLine("Transfer fails. {0} -> {1}. Error message:{2}", e.Source, e.Destination, e.Exception.Message);
    }

    private static void FileSkippedCallback(object sender, TransferEventArgs e)
    {
        Console.WriteLine("Transfer skips. {0} -> {1}.", e.Source, e.Destination);
    }

示例中缺少的是如果处理现有图像不同的处理方式。

我不确定这是否在版本0.3中可用,但我也在安装版本0.4.1 Microsoft.WindowsAzure.Storage.DataMovement包后才知道。下面的代码将比较来源和目的地,并决定是否应该覆盖。

   context.ShouldOverwriteCallback = (source, destination) =>
                    {
                      if(TransferContext.Equals(source, destination)==true)
                            return false;
                      else
                            return true;                        

                    };

答案 1 :(得分:0)

您是否向TransferManager添加了多个具有相同源/目标的传输任务(例如,在您的应用程序中多次运行代码)。如果是这样,您将遇到问题,因为DMlib不允许同时运行具有相同源/目的地的多个传输任务。

答案 2 :(得分:0)

以下是运行上传10次的代码。请根据您的要求进行修改。 请注意,您需要等待之前的任务完成,然后添加具有相同源和目标的新传输任务以及新的传输上下文。

        for (int i = 0; i < 10; i++)
        {
            // Create Transfer Context
            DirectoryTransferContext context = new DirectoryTransferContext();

            //if dest blob exist just overwrite it 
            context.ShouldOverwriteCallback = TransferContext.ForceOverwrite;

            // Start the upload and wait for it to finish
            Task<TransferStatus> task = TransferManager.UploadDirectoryAsync(sourceDirPath, destDir, options, context);
            task.Wait();

            //Add some code to check the task.Result, following code only print the result
            Console.WriteLine(string.Format("{0}\t{1}\t{2}\t{3}", task.Result.NumberOfFilesTransferred, task.Result.NumberOfFilesFailed, task.Result.NumberOfFilesSkipped, task.Result.BytesTransferred));
        }