日期:2008-11-29  浏览次数:20424 次


在asp.net中执行一个长时间的操作,有的时候需要在在客户端有一个反馈能了解到任务的执行进度,大致看了一下有这么几种做法:
(1)按下按钮的时候给出一个<div>提示正在执行任务,执行完毕让这个<div>隐藏
(2)按下按钮的时候跳转到一个提示任务正在执行的页面,执行完毕了再跳转回来
(3)做一个任务类,开启另外一个线程执行任务,同时在客户端或者服务器端保存这个类的实例来跟踪任务的执行情况

(1)和(2)的情况用的比较多,也比较简单,缺点是不能实时的知道任务的执行进度,而且时间一长可能会超时,(3)的方法就会比较好的解决上面说的2个缺点。下面着重说一下(3)的实现方法,先从简单开始,我们做一个任务类,在客户端时时(暂且刷新时间为1秒)得知任务执行了多少时间,并且在成功完成任务后给出执行时间,在任务出错的时候给出出错的时间。

前台

<form id="Form1" method="post" runat="server">
<asp:label id="lab_state" runat="server"></asp:label><br>
<asp:Button id="btn_startwork" runat="server" Text="运行一个长时间的任务"></asp:Button>
</form>

后台

先是一些类的申明:
protected System.Web.UI.WebControls.Button btn_startwork;
protected System.Web.UI.WebControls.Label lab_state;
//前面2个是vs.net自己生成的
protected work w;

在Page_Load里面输入以下代码:

if(Session["work"]==null)
   {
    w=new work();
    Session["work"]=w;
   }
   else
   {
    w=(work)Session["work"];
   }
   switch(w.State)
   {
    case 0:
    {
     this.lab_state.Text="还没有开始任务";
     break;
    }
    case 1:
    {
     this.lab_state.Text="任务进行了"+((TimeSpan)(DateTime.Now-w.StartTime)).TotalSeconds+"秒";
     this.btn_startwork.Enabled=false;
     Page.RegisterStartupScript("","<script>window.setTimeout('location.href=location.href',1000);</script>");
     //不断的刷新本页面,随时更新任务的状态
     break;
    }
    case 2:
    {
     this.lab_state.Text="任务结束,并且成功执行所有操作,用时"+((TimeSpan)(w.FinishTime-w.StartTime)).TotalSeconds+"秒";
     this.btn_startwork.Enabled=true;
     break;
    }
    case 3:
    {
     this.lab_state.Text="任务结束,在"+((TimeSpan)(w.ErrorTime-w.StartTime)).TotalSeconds+"秒的时候发生错误导致任务失败";
     this.btn_startwork.Enabled=true;
     break;
    }
   }

在按钮单击事件内输入以下代码:

if(w.State!=1)
   {
    this.btn_startwork.Enabled=false;
    w.runwork();
    Page.RegisterStartupScript("","<script>location.href=location.href;</script>");
    //立即刷新页面
   }

另外建立一个任务类,代码如下:

public class work
 {
  public int State=0;//0-没有开始,1-正在运行,2-成功结束,3-失败结束
        public DateTime StartTime;
  public DateTime FinishTime;
  public DateTime ErrorTime;

  public void runwork()
  {
   lock(this)//确保临界区被一个Thread所占用
   {
    if(State!=1)
    {
     State=1;
     StartTime=DateTime.Now;
     System.Threading.Thread thread=new System.Threading.Thread(new System.Threading.ThreadStart(dowork));
     thread.Start();                        
    }
   }
  }

  private void dowork()
  {
   try
   {
    SqlConnection conn=new SqlConnection(System.Configuration.ConfigurationSettings.AppSettings["conn"]);
    SqlCommand cmd=new SqlCommand("Insert Into test (test)values('test')",conn);
    c