CopyToAsync下载图片后FluentFTP上传报错,如何用async/await解决
问题修复方案
问题根源
- 调用异步方法
DownloadImage时未添加await关键字,导致下载逻辑未执行完成就提前执行后续文件检查和FTP上传逻辑 DownloadImage内部混用阻塞式调用.Result和await,既可能引发线程死锁,也会打乱异步执行时序- 未对下载失败的场景做处理,可能出现下载未成功但后续逻辑仍然执行的情况
修复步骤
1. 修正DownloadImage方法的异步实现
调整异步调用逻辑,优化路径拼接,增加下载结果返回:
// 可根据需要修改返回值,示例返回下载成功的完整路径,失败返回null public static async Task<string> DownloadImage(Entity.LoginResult loginResult, string saveFolder, string image, string saveFile) { string filename = Path.GetFileNameWithoutExtension(saveFile); string extension = Path.GetExtension(saveFile); saveFile = GetValidUrlString(filename, "-", 255) + extension; // 用Path.Combine拼接路径,避免手动拼接斜杠出错 string fullSavePath = Path.Combine(saveFolder, saveFile); // 注意:生产环境建议复用HttpClient静态实例,不要每次请求都new,避免端口耗尽问题 using (var httpClient = new HttpClient()) { using (var request = new HttpRequestMessage(HttpMethod.Get, apiUrl + image + "/download")) { request.Headers.TryAddWithoutValidation("Authorization", "CBX-SIMPLE-TOKEN Token=" + loginResult.token); // 替换阻塞式.Result为await,符合异步开发规范 var response = await httpClient.SendAsync(request); if (response.StatusCode == System.Net.HttpStatusCode.OK) { using (var fs = new FileStream(fullSavePath, FileMode.Create)) { await response.Content.CopyToAsync(fs); } return fullSavePath; } return null; } } }
2. 修正调用逻辑,等待下载完成再执行后续操作
// 调用时必须添加await,等待下载逻辑完全执行完成后再走后续流程 var downloadedFilePath = await DownloadImage(loginResult, saveFolder, image, saveFile); // 直接判断返回的路径有效性即可 if (!string.IsNullOrEmpty(downloadedFilePath) && File.Exists(downloadedFilePath)) { // 此时文件已经完成写入、流已经自动释放,不会出现文件占用问题,直接执行FTP上传 CallFtpUpload(downloadedFilePath); }
补充说明
- await执行完成后,
FileStream的using块已经自动释放文件锁,不会出现文件被占用的问题 - 如果需要兼容非异步上下文的调用场景,可以用
DownloadImage(...).GetAwaiter().GetResult()代替.Result避免死锁,优先推荐全链路使用await - 可根据业务需要添加下载失败重试逻辑,避免偶发网络问题导致流程中断
内容的提问来源于stack exchange,提问作者user2435866
相关产品推荐
相关产品推荐

