博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C# 中 async/await 调用传统 Begin/End 异步方法
阅读量:5744 次
发布时间:2019-06-18

本文共 3140 字,大约阅读时间需要 10 分钟。

最近在改进园子的图片上传程序,希望实现用户上传图片时同时将图片文件保存在三个地方:1)服务器本地硬盘;2)又拍云;3)阿里云OSS。并且在保存时使用异步操作。

对于异步保存到本地硬盘,只需用 Steam.CopyToAsync() 将上传文件流异步复制到 FileStream 即可。

对于异步保存至又拍云,只要借助 WebRequest.GetRequestStreamAsync() + Steam.CopyToAsync() 就可以实现。

而阿里云OSS提供了 .NET SDK,使用起来很方便,但是之前并没有提供异步接口,成为异步化的一个障碍。

今天在 OSS .NET SDK 的更新日志中惊喜地发现:“添加异步化接口(支持Put/Get/List/Copy/PartCopy等异步操作)”。于是立马下载下来,可是一使用惊喜瞬间化为乌有 —— 新版 SDK 只提供了传统的 Begin/End 异步接口,却没有提供 async 异步接口。

public IAsyncResult BeginPutObject(string bucketName, string key, Stream content, AsyncCallback callback, object state);
public PutObjectResult EndPutObject(IAsyncResult asyncResult);

怀着失落的心情,望着孤零零的没有 await 陪伴的 async,心里有说不出的滋味。。。

async Task
IBucket.PutFileAsync(string filePath, Stream uploadStream){ filePath = filePath.Substring(1); uploadStream.Position = 0; _client.PutObject(_bucketName, filePath, uploadStream); return true;}

难道这次只能实现半吊子的异步化吗?好不容易等来 OSS .NET SDK 支持异步化,难道只是空欢喜一场吗?真有些不甘心啊!

这时,心中突然闪过一个念头:有没有可能直接用 async/await 调用 Begin/End 异步方法?也许微软早就为我们准备好了馅饼?

于是,在网上搜寻了一番,发现了一线希望 —— 用 Task.Factory.FromAsync() 是可能实现的。

可是,一堆 FromAsync 方法看着就让人晕,只能一点点去试。

开始用的是 Task.Factory.FromAsync<PutObjectResult> ,但参数总对不上,比如:

await Task.Factory.FromAsync
( _client.BeginPutObject, _client.EndPutObject, _bucketName, filePath, uploadStream, null);

编译出错:

No overload for method 'FromAsync' takes 6 arguments

后来改为下面这样,总算编译通过了:

await Task.Factory.FromAsync
( _client.BeginPutObject(_bucketName, filePath, uploadStream, null, null), x => { return _client.EndPutObject(x); });

而且运行程序,图片都能成功上传到阿里云OSS中,但总是报这样的错误:

failed: System.ArgumentException : retryableAsyncResult should not be null	at Aliyun.OpenServices.OpenStorageService.Utilities.OssUtils.EndOperationHelper(IServiceClient serviceClient, IAsyncResult asyncResult)

这个错误说明 callback 调用没成功。

在这个地方折腾了很长时间,后来瞎猫碰着死耗子,把 Task.Factory.FromAsync<PutObjectResult> 改为 Task<PutObjectResult>.Factory.FromAsync 问题就解决了。代码如下:

async Task
IBucket.PutFileAsync(string filePath, Stream uploadStream){ filePath = filePath.Substring(1); uploadStream.Position = 0; var result = await Task
.Factory.FromAsync( _client.BeginPutObject, _client.EndPutObject, _bucketName, filePath, uploadStream, null); Console.WriteLine(result.ETag); return true;}

【2017-7-25更新】

感谢评论中 @唐诗 的建议!TaskCompletionSource 的确是更好的解决方法,最新的实现代码如下:

Task
IBucket.PutFileAsync(string filePath, Stream uploadStream, string contentType){ filePath = filePath.Substring(1); uploadStream.Position = 0; var tcs = new TaskCompletionSource
(); _client.BeginPutObject(_bucketName, filePath, uploadStream, new ObjectMetadata { ContentType = contentType }, asyncResult => { _client.EndPutObject(asyncResult); tcs.SetResult(true); }, null); return tcs.Task;}

转载于:https://www.cnblogs.com/dudu/p/async_await_call_begin_end_method.html

你可能感兴趣的文章
ps6-工具的基础使用
查看>>
linux下使用过的命令总结(未整理完)
查看>>
时间助理 时之助
查看>>
英国征召前黑客组建“网络兵团”
查看>>
PHP 命令行模式实战之cli+mysql 模拟队列批量发送邮件(在Linux环境下PHP 异步执行脚本发送事件通知消息实际案例)...
查看>>
pyjamas build AJAX apps in Python (like Google did for Java)
查看>>
centos5.9使用RPM包搭建lamp平台
查看>>
Javascript String类的属性及方法
查看>>
[LeetCode] Merge Intervals
查看>>
Struts2 学习小结
查看>>
测试工具综合
查看>>
【记录】JS toUpperCase toLowerCase 大写字母/小写字母转换
查看>>
在 Linux 系统中安装Load Generator ,并在windows 调用
查看>>
Visifire charts ToolBar
查看>>
Mysql查询
查看>>
数据传输流程和socket简单操作
查看>>
ProbS CF matlab源代码(二分系统)(原创作品,转载注明出处,谢谢!)
查看>>
OC中KVC的注意点
查看>>
JQ入门(至回调函数)
查看>>
【洛天依】几首歌的翻唱(无伴奏)
查看>>