首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如果并行执行多个DownloadToAsync调用,如何捕获RequestFailedException?

如果并行执行多个DownloadToAsync调用,如何捕获RequestFailedException?
EN

Stack Overflow用户
提问于 2021-06-23 15:32:02
回答 2查看 69关注 0票数 1

我有一些这样的代码:

代码语言:javascript
运行
AI代码解释
复制
public async Task<IEnumerable<Response>> SaveFiles(IEnumerable<string> filePaths)
{
    var baseFolder = "C:\\Temp";
    var fullTempPath = $"{baseFolder}\\{Guid.NewGuid()}";
    var fileDirectory = Directory.CreateDirectory(fullTempPath);

    Task<Response>[] tasks = new Task<Response>[filePaths.Count()];

    for (int i = 0; i < filePaths.Count(); i++)
    {
        var blobClientDetails = GetBlobClientDetails(filePaths.ElementAt(i));
        var credentials = new AzureSasCredential(blobClientDetails.Value);
        var blob = new BlobClient(blobClientDetails.Key, credentials);
        tasks[i] = blob.DownloadToAsync(fileDirectory.FullName);
    }

    return await Task.WhenAll(tasks);
}

private KeyValuePair<Uri, string> GetBlobClientDetails(string filePath)
{
    var filePathExcludingSAS = filePath.Substring(0, filePath.IndexOf('?'));
    var sasToken = filePath.Substring(filePath.IndexOf('?') + 1);

    return new KeyValuePair<Uri, string>(new Uri(filePathExcludingSAS), sasToken);
}

其原理是,这将在等待前一个文件的下载完成之前触发每个文件的下载,因此最后会出现Task.WhenAll(tasks)。但是,我希望能够准确地捕获异常,并能够指定下载失败的文件。我该怎么做呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-06-23 17:06:26

感谢Theodor到目前为止的帮助。我已经创建了这样的东西,目前还没有测试,我想知道它是否真的是异步的。

代码语言:javascript
运行
AI代码解释
复制
public async Task<IEnumerable<DownloadResult>> SaveFiles(IEnumerable<string> filePaths)
{
    var baseFolder = ConfigurationManager.AppSettings["tempFolderLocation"];
    var fullTempPath = $"{baseFolder}\\{Guid.NewGuid()}";
    var fileDirectory = Directory.CreateDirectory(fullTempPath);
    var tasks = filePaths.Select(fp => DownloadFile(fp, fileDirectory.FullName));
    return await Task.WhenAll(tasks);
}

我已经添加了一个'DownloadFile‘方法,它现在为每个文件执行该操作,并返回一个任务:

代码语言:javascript
运行
AI代码解释
复制
private async Task<DownloadResult> DownloadFile(string filePath, string directory)
{
    var blobClientDetails = GetBlobClientDetails(filePath);
    var credentials = new AzureSasCredential(blobClientDetails.Value);
    var blob = new BlobClient(blobClientDetails.Key, credentials);

    try
    {
        var response = await blob.DownloadToAsync(directory);
        return new DownloadResult(true, response);
    }
    catch (RequestFailedException ex)
    {
        // do some additional logging of the exception.
        return new DownloadResult(false, null, ex.Message);
    }
}

下面是DownloadResult:

代码语言:javascript
运行
AI代码解释
复制
public class DownloadResult
{
    public DownloadResult(bool isSuccessful, Response response, string errorMessage = "")
    {
        IsSuccessful = isSuccessful;
        Response = response;
        ErrorMessage = errorMessage;
    }

    public bool IsSuccessful { get; set; }
    public Response Response { get; set; }
    public string ErrorMessage { get; set; }
}
票数 1
EN

Stack Overflow用户

发布于 2021-06-23 16:54:25

LINQ Select运算符使得将本机任务投影到具有一些额外功能的自定义任务变得很容易。在这种情况下,额外的功能是将RequestFailedException包装在自定义异常类型中:

代码语言:javascript
运行
AI代码解释
复制
public async Task<Response[]> SaveFiles(IEnumerable<string> filePaths)
{
    var baseFolder = "C:\\Temp";
    var fullTempPath = $"{baseFolder}\\{Guid.NewGuid()}";
    var fileDirectory = Directory.CreateDirectory(fullTempPath);

    Task<Response>[] tasks = filePaths.Select(async filePath =>
    {
        var blobClientDetails = GetBlobClientDetails(filePath);
        var credentials = new AzureSasCredential(blobClientDetails.Value);
        var blob = new BlobClient(blobClientDetails.Key, credentials);
        try
        {
            return await blob.DownloadToAsync(fileDirectory.FullName);
        }
        catch (RequestFailedException ex)
        {
            throw new FileDownloadException(ex.Message, ex) { FilePath = filePath };
        }
    }).ToArray();

    Task<Response[]> whenAll = Task.WhenAll(tasks);
    try { return await whenAll; }
    catch { whenAll.Wait(); throw; } // Propagate AggregateException
}

FileDownloadException类:

代码语言:javascript
运行
AI代码解释
复制
public class FileDownloadException : Exception
{
    public string FilePath { get; init; }
    public FileDownloadException(string message, Exception innerException)
        : base(message, innerException) { }
}

然后,您可以像这样使用SaveFiles方法:

代码语言:javascript
运行
AI代码解释
复制
try
{
    Response[] responses = await SaveFiles(filePaths);
}
catch (AggregateException aex)
{
    foreach (var ex in aex.InnerExceptions)
    {
        if (ex is FileDownloadException fileEx)
        {
            // Our special exception wrapper
            Console.WriteLine($"{fileEx.FilePath} => {fileEx.InnerException.Message}");
        }
        else
        {
            // Something else happened (not a RequestFailedException)
            Console.WriteLine($"{ex.Message}");
        }
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68102901

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档