private void DownLoadFile(string path, EmailMessage email, Attachment at) { try { Attachment attachment = email.Attachments.Single(x => x.ContentId == at.ContentId); attachment.Load(); FileAttachment fileAttachment = attachment as FileAttachment; fileAttachment.Load(); byte[] bytes = fileAttachment.Content; File.WriteAllBytes(path, bytes); } catch (Exception ex) { } } public async System.Threading.Tasks.Task<ExchangeEmail> GetBody(ItemId Id) { EmailMessage email = EmailMessage.Bind(service, Id); #region xiaolu Add 15-7-8 附件内容 Dictionary<string, string> atts = new Dictionary<string, string>(); if (email.HasAttachments) { var att = email.Attachments; foreach (var at in att) { var guid = Guid.NewGuid().ToString(); var ext = at.Name.Substring(at.Name.LastIndexOf(".")); var linpath = "http://" + HttpContext.Current.Request.Url.Host + ":" + HttpContext.Current.Request.Url.Port + "/UpLoad/App/Mail/" + guid + ext;//连接地址 atts.Add(linpath, at.Name); var path = HttpContext.Current.Server.MapPath("~/UpLoad/App/Mail/" + guid + ext);//保存的文档路径 await System.Threading.Tasks.Task.Run(() => { DownLoadFile(path, email, at); }); } } #endregion ExchangeEmail mee = new ExchangeEmail(); mee.Body = email.Body; mee.DateTimeCreated = email.DateTimeCreated; mee.DateTimeReceived = email.DateTimeReceived; mee.Id = email.Id; mee.Sender = email.Sender.Name; mee.Subject = email.Subject; mee.Atts = atts; mee.SenderEmail = email.Sender.Address; //mee.Body = email.TextBody; return mee; }
如上代码,加了async和await,但是调试时发现代码都是执行完下载代码后才往后执行的,初次使用望指点。
解决方案
10
去掉await再试一次
10
await的中文翻译为:等待
你加了等待,当然要先下载完,才会运行后续的指令。
await System.Threading.Tasks.Task.Run(() => { DownLoadFile…
// 后续指令…
你加了等待,当然要先下载完,才会运行后续的指令。
await System.Threading.Tasks.Task.Run(() => { DownLoadFile…
// 后续指令…
10
异步出现在调用 GetBody 的地方(你根本没有贴出来的部分),而不是在它内部。在 GetBody 内部,是异步回调的,在还没有执行完 foreach 的时候,GetBody 的调用者的后续代码就提前执行了。那才是你应该贴出来、应该调试的。
async/await 实际上是障眼法,让人混乱。假如你没有普通的多线程异步回调的知识和丰富的测试调试经验,那么 async/await 实际上很容易误导你的思路。用一个“看似顺序的程序代码”来实现异步多线程编程,这要求一个人有更高的抽象编程能力,而并不像微软某些讲师吹嘘de那样是“降低技术要求”的。虽然代码简单了,但是调试和测试更难了。
10
调用async方法时,await关键字会自动暂停当前线程中任何其他活动,直到任务完成,离开调用线程,这是精通C#(第6版)上的原话,网上有这本书,你可以下载下来看一下http://www.jb51.net/books/327829.html
10
假设一种情景,你做的一个桌面端程序,有一个按钮,点击这个按钮后去上传一个文件(文件很大要很久),为不让用户等待 只能后台下,上传完文件得到的路径还需要保存的数据库里面,同时还需要记录日志。
整体来说三件事
1.后台下载文件,下载完后有后续处理流程–起来一个线程跑,跑完需要有回调把得到的文件地址存到数据库中,但也与主线程(UI)无关
2.记录日志,纯操作日志,成功与否与业务流程无关–这个直接起来一个线程去跑,跑完就跑完了 没有回调并且与主线程无关
3.界面正常响应
整体来说三件事
1.后台下载文件,下载完后有后续处理流程–起来一个线程跑,跑完需要有回调把得到的文件地址存到数据库中,但也与主线程(UI)无关
2.记录日志,纯操作日志,成功与否与业务流程无关–这个直接起来一个线程去跑,跑完就跑完了 没有回调并且与主线程无关
3.界面正常响应
void 按钮点击事件响应方法() { 用线程池起来一个线程记录日志;//不阻塞 无回调 上传文件并处理方法();//不阻塞 看似没有回调,其实回调放到了这个方法里面 } async void 上传文件并处理方法() //此处async理解为这是一个与主线程无关的处理流程 { string newURL=await 上传文件方法(); 数据库保存新文件地址方法();//这个理解为上传文件方法执行完后,根据他的返回值执行的回调 } Task<string> 上传文件方法() { return Task.Run(() => { // 具体的上传文件逻辑 return 上传文件后得到的新地址; }); }