C# 中 async/await 调用传统 Begin/End 异步方法
最近在改进园子的图片上传程序,希望实现用户上传图片时同时将图片文件保存在三个地方: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<bool> IBucket.PutFileAsync(string filePath, Stream uploadStream)
{
filePath = filePath.Substring();
uploadStream.Position = ;
_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<PutObjectResult>(
_client.BeginPutObject,
_client.EndPutObject,
_bucketName, filePath, uploadStream,
null);
编译出错:
No overload for method 'FromAsync' takes 6 arguments
后来改为下面这样,总算编译通过了:
await Task.Factory.FromAsync<PutObjectResult>(
_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<bool> IBucket.PutFileAsync(string filePath, Stream uploadStream)
{
filePath = filePath.Substring();
uploadStream.Position = ;
var result = await Task<PutObjectResult>.Factory.FromAsync(
_client.BeginPutObject,
_client.EndPutObject,
_bucketName, filePath, uploadStream,
null);
Console.WriteLine(result.ETag);
return true;
}
【2017-7-25更新】
感谢评论中 @唐诗 的建议!TaskCompletionSource 的确是更好的解决方法,最新的实现代码如下:
Task<bool> IBucket.PutFileAsync(string filePath, Stream uploadStream, string contentType)
{
filePath = filePath.Substring();
uploadStream.Position = ; var tcs = new TaskCompletionSource<bool>(); _client.BeginPutObject(_bucketName,
filePath,
uploadStream,
new ObjectMetadata { ContentType = contentType },
asyncResult =>
{
_client.EndPutObject(asyncResult);
tcs.SetResult(true);
},
null); return tcs.Task;
}
C# 中 async/await 调用传统 Begin/End 异步方法的更多相关文章
- C#中async/await中的异常处理
在同步编程中,一旦出现错误就会抛出异常,我们可以使用try-catch来捕捉异常,而未被捕获的异常则会不断向上传递,形成一个简单而统一的错误处理机制.不过对于异步编程来说,异常处理一直是件麻烦的事情, ...
- [翻译] Python 3.5中async/await的工作机制
Python 3.5中async/await的工作机制 多处翻译出于自己理解,如有疑惑请参考原文 原文链接 身为Python核心开发组的成员,我对于这门语言的各种细节充满好奇.尽管我很清楚自己不可能对 ...
- 关于C#中async/await中的异常处理(下)-(转载)
上一篇文章里我们讨论了某些async/await的用法中出现遗漏异常的情况,并且谈到该如何使用WhenAll辅助方法来避免这种情况.WhenAll辅助方法将会汇总一系列的任务对象,一旦其中某个出错,则 ...
- 关于C#中async/await中的异常处理(上)-(转载)
在同步编程中,一旦出现错误就会抛出异常,我们可以使用try…catch来捕捉异常,而未被捕获的异常则会不断向上传递,形成一个简单而统一的错误处理机制.不过对于异步编程来说,异常处理一直是件麻烦的事情, ...
- 关于C#中async/await中的异常处理(上)
关于C#中async/await中的异常处理(上) 2012-04-11 09:15 by 老赵, 17919 visits 在同步编程中,一旦出现错误就会抛出异常,我们可以使用try…catch来捕 ...
- Vue实例中封装api接口的思路 在页面中用async,await调用方法请求
一般我们写小型的项目是用不到封装axios实例 但是当我们写大型项目时 接口有时候多到有上百个接口,那我们在请求一次调用一次接口,接口上好多都是重复的,这个时候我们就可以封装axios实例,既节省了 ...
- 关于 ASP.NET Web 应用中 async/await 注意问题
System.NullReferenceException: Object reference not set to an instance of an object. at System.Web.T ...
- springcloud中servcie层调用fegin异常以及异步方法的实现
近日在做业务上的短信推送和APP消息推送,通过调用别的模块的接口来实现,在springcloud中通过fegin进行调用.这里要说明的事情并不是如何开发推送功能,而是在调试过程中碰到的一些小问题.我把 ...
- js中回调函数,promise 以及 async/await 的对比用法 对比!!!
在编程项目中,我们常需要用到回调的做法来实现部分功能,那么在js中我们有哪些方法来实现回调的? 方法1:回调函数 首先要定义这个函数,然后才能利用回调函数来调用! login: function (f ...
随机推荐
- 简单的javascript--test2
插件: jquery, sweetalert (http://t4t5.github.io/sweetalert/ ) 1.index.html <!DOCTYPE HTML> <h ...
- VC++ chap13 文档与串行化
Lesson 13 文档与串行化 13.1使用CArchive类对文件进行读写操作 //让对象数据持久性的过程称之为串行化,或者序列化 void CGraphicView::OnFileWrite() ...
- Android文件系统的结构
Android 4.2.2 版本的文件系统 内核版本为 3.0.31 版本号为JDQ39 factory//估计是存放网络通信协议的登录密钥的|-- bluetooth|-- hdcp.keys|-- ...
- OC 框架组织架构图
- Java课程实验报告 实验一 Java开发环境的熟悉
北京电子科技学院(BESTI) 实 验 报 告 课程:Java程序设计 班级:1353 姓名:韩玉琪 学号:20135317 成绩: 指导教师:娄嘉鹏 实 ...
- 通过反射向将EF的实体映射配置加入到实体模型中
public AdminDbContext() : base("MemberDbContext") { //不使用代理创建导航属性,避免WCF序列化错误 Configuration ...
- 普林斯顿结构 VS 哈佛结构
1. 冯·诺依曼结构 冯·诺依曼结构,又称为普林斯顿体系结构,是一种将程序指令存储器和数据存储器合并在一起的存储器结构.取指令和取操作数都在同一总线上,通过分时复用的方式进行:缺点是在高速运行时,不能 ...
- 动态获取ul,li的数据
通过一个小例子讲下动态获取li标签的数据,前台页面原有样式: <div class="flone"> <ul class="fltwo"> ...
- memcache与memcached介绍及安装配置
也许大家一看到Memcache和Memcached会有点晕,这两者有什么关系又有什么区别呢,下面先给大家说下Memcached,Memcached是一个高性能的分布式内存对象缓存系统,用于动态Web应 ...
- Java泛型总结(转)
本文是转载,原文链接:http://www.cnblogs.com/lwbqqyumidi/p/3837629.html 一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下面这段简短的代码: ...