耗时很长的服务器端事件中让客户端得到中间过程信息的合理解决方案

需求:
B/S结构的系统里,用户点一个按钮系统开始发送上千封邮件,要求把发送信息(发送成功数,失败数,剩余数量...)动态实时的反馈给客户.

分析和实施过程当中遇到的问题:

一:最低级的问题
由于客户催的紧,发邮件的核心代码写好后就开始给他使用了,当时系统还没上AJAX.

最初的问题是一点按钮过不了几分钟就页面超时(要想页面不超时必须定时给页面输出一些东西),
搞定了页面超时的问题然后就是服务器IIS超时
设置了IIS超时时间就又SQL连接超时

最后寻思这样下去总不是个办法
决定上ajax(正如大家想的一样)

二:开始想到了ajax
上ajax又碰到一个问题
ICallbackEventHandler只提供了两个方法,
一个是被客户端触发的服务器端事件,

一个是服务器端事件完成后的反馈事件
两个事件是顺序发生的,

我如果在一个事件中执行发送邮件的过程,

我就不能在这个事件中把中间过程的信息反馈给客户
我的两个需求必须同时进行!
我甚至想到:当用户点按钮的时候同时触发ajax事件和postback事件,

多么愚蠢的idea啊(回发了还怎能异步刷新)
最后:多方求助+苦思冥想最后得出两种解决方案

1.通过ajax每次发送一定数量的邮件
用javascript循环把邮件地址发送给服务器端(以ajax方式),

每循环一次给服务器端10条信息,

服务器端把这10个邮件发完之后,反馈客户端一次

客户端通过js更新提示信息(已经发完十封了)
然后进入下一次ajax循环

2.ajax调用服务器端事件,在服务器端事件里使用多线程技术
当用户点按钮触发了ajax服务器端事件后,

在这个事件里我建立了两个线程
一个线程开始发送邮件,另一个线程负责返回信息

因为要实时的返回信息,

所以这个ajax事件肯定是定时调用的.(我是每4秒获取一下服务器端的信息)
服务器端事件开始执行,

先判断发邮件的线程是否已经开始了,

如果没开始就建立发邮件的线程,

并执行线程
如果开始了(那么说明这个调用肯定不是第一次调用)
就执行反馈信息的代码

两种方案都是可行的,我最终选择了第二种

想法随好,在实施过程中又碰到了N多问题

 三.实施过程中的问题
1.假如在发送过程中用户出现了断网,或者不小心关闭了页面,我怎么让他下次登陆的时候继续发送.

在这里我想到了消息队列,事务等,最终的解决方案是
开始发邮件前先把所有待发的邮件存储到数据库的一个临时表里去,

发一封删除一条记录,

pagelodad里检测该表是否有记录,

如果有记录就直接发送该表里的邮件(也就是尚未完成的邮件)

这里可以用Page.ClientScript.RegisterStartupScript注册一个客户端事件调用我们的ajax函数


2.线程的参数问题

发送邮件的线程方法是肯定需要参数的,然而new Thread(new ThreadStart());创建线程的又不允许给线程传参数,

这个问题没有困绕我很久,因为网上有很多解决方案,比如建立一些public的变量或者属性

我用的是另外一种办法,先建立一个对象,然后给这个对象的属性负值(这就是我的参数啦)

然后创建线程的时候线程的方法是这个对象的一个方法sendmail_thread = new Thread(new ThreadStart(sendobj.sendmail_xuan));


3.线程开始状态判断的误区
线程有一个ThreadState属性,我不建议用这个属性的IsAlive判断线程是否开始.
因为代码执行到sendmail_thread = new Thread(new ThreadStart(sendobj.sendmail_xuan));这句后,

线程并不一定处于IsAlive状态,因为他要等服务器的CPU给他分配时间片(具体的我就不说了)
我是用session判断的

 

4.还是线程的问题

当用户执行了操作,有可能发送邮件的线程还没有开始,而ajax已经去取返回信息了.
(如果计算发送成功率,有可能造成除以0的错误)
或者邮件发送线程已经完成了操作,但ajax还一直在那取后端的反馈信息

(如果反馈发送消耗时间,有可能时间会一直增长)

人们都说网页上的多线程不好搞(每个访问就有可能造成一个线程)

果然如此啊,我这里还没考虑高并发的问题,

然而上面说的那两个问题都不是硬伤,

想想办法还是可以"掩饰"过去的

 

文章就写到这,我没有公布原代码,只是写了一些思想和解决方法

实在是我这个案例有点偏了.大家如果一定要原代码,那么就在此文章下留言吧

如果要的人超过10个我就写这个文章的续

 

另:系统开发过程中得到了Jeffrey Zhao  joseph.zhu(asp.net第一步的作者)  南洋 的帮助   在此表示感谢

8.19日为了阅读方便,我对文章做了一些修改,主要内容未变

原文地址:https://www.cnblogs.com/liulun/p/1269675.html