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 ...
随机推荐
- CentOS6.5 Openssl版本升级
CentOS6.5 Openssl 升级: 第一步:在openssl官网(https://www.openssl.org/)下载最新版 Ps:个人使用的是openssl-1.0.1u.tar.gz版 ...
- TJI读书笔记11-多态
TJI读书笔记11-多态 再说说向上转型 多态的原理 构造器和多态 协变返回类型 使用继承进行设计 多态是数据抽象和继承之后的第三种基本特征. 一句话说,多态分离了做什么和怎么做(再次对埃大爷佩服的五 ...
- HTTP的应用httpclient 和线程
package com.example.service; import java.io.IOException; import java.io.InputStream; import org.apac ...
- exports 和 module.exports 的区别
https://cnodejs.org/topic/5231a630101e574521e45ef8 //一句话总结:exports是对module.exports的引用,require()返回的是 ...
- git常用操作
批量删除以bran开头的本地分支 git branch |grep 'bran'|xargs git branch -d
- python模块使用案例
python模块使用案例 一.使用MySQLdb模块代码示例: # 导入 MySQLdb模块 import MySQLdb # 和服务器建立链接,host是服务器ip,我的MySQL数据库搭建在本机, ...
- 开发中用到的开源框架汇总(Updating)
SuperWebSocket SuperSocket NPOI 官网:http://npoi.codeplex.com/ 实例讲解:http://www.cnblogs.com/yutian/p/52 ...
- NSMutableAttributedString(改变文字颜色)
//类型 //创建一个label UILabel *label1=[[UILabel alloc]initWithFrame:CGRectMake(130, 60,250, 150)]; ...
- C#语法灵活运用之排列组合算法
今天群里有朋友求一个排列组合算法,题目是给定长度,输出所有指定字母的组合. 如指定字母a.b.c.d.e.f,长度为2,则结果应为:aa.ab.ac ... ef.ff. 有朋友给出算法,很有特色: ...
- Decorator(装饰)-对象结构型模式
1.意图 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. 2.别名 包装器 Wrapper. 3.动机 给某个对象而不是整个类添加一些功能.一个较为灵 ...