2009年3月3日 星期二

ASP.NET: 長時間的工作,取得目前進度到第n筆

在 asp.net 的應用程式中,最怕的一種需求,莫過於大量資料匯入,客戶又要求以 Web form 來呈現,並要求匯入的進度。

也就是說,畫面需要呈現目前進行到第幾筆,總共幾筆。

以下是我的實作。 實作分成兩部份,一個是伺服器端的同步,也就是一般的寫法。另一個則是伺服器端的非同步。

在 asp.net 的應用程式中,最怕的一種需求,莫過於大量資料匯入,客戶又要求以 Web form 來呈現,並要求匯入的進度。

也就是說,畫面需要呈現目前進行到第幾筆,總共幾筆。

以下是我的實作。 實作分成兩部份,一個是伺服器端的同步,也就是一般的寫法。另一個則是伺服器端的非同步。

aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default"
  Async="true" AsyncTimeout="1" %>




  

  



  

Code Behind

using System;
using System.Web.Script.Services;
using System.Web.Services;
using System.Web.UI;

namespace WebApplication1
{
  public partial class _Default : System.Web.UI.Page
  {
    private static SlowTask slowTask = null;

    protected void Page_Load(object sender, EventArgs e)
    {

    }

    [ScriptMethod]
    [WebMethod]
    public static string GetTaskCurrentProgress()
    {
      return string.Format("{0}/{1} : {2}", slowTask.CurrentCount, slowTask.TotalCount, 
        slowTask.GetAsyncTaskProgress());
    }

    public void RunItAsync()
    {
      slowTask = new SlowTask(1000);
      PageAsyncTask asyncTask1 = new PageAsyncTask(slowTask.OnBegin, slowTask.OnEnd, null, "Async", true);
      RegisterAsyncTask(asyncTask1);
    }

    [ScriptMethod]
    [WebMethod]
    public static void RunItSync()
    {
      slowTask = new SlowTask(1000);
      slowTask.ExecuteAsyncTask();
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
      RunItAsync();
      Page.ClientScript.RegisterStartupScript(typeof(string), "ok", "");
    }
  }
}

關於 SlowTask 的程式如下,主要是封裝長時間工作的內容

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading;

namespace WebApplication1
{
  public class SlowTask
  {
    private readonly int totalCount;
    public int TotalCount
    {
      get
      {
        return totalCount;
      }
    }

    public SlowTask(int count)
    {
      totalCount = count;
    }
    private String taskGrogress;
    private AsyncTaskDelegate dlgt;

    protected delegate void AsyncTaskDelegate();

    public String GetAsyncTaskProgress()
    {
      return taskGrogress;
    }

    public void ExecuteAsyncTask()
    {
      Random r = new Random(5);
      for (int i = 0; i < totalCount; i++)
      {
        Thread.Sleep(10 * r.Next(5));
        CurrentCount++;
      }
    }

    public int CurrentCount { get; set; }

    public IAsyncResult OnBegin(object sender, EventArgs e,
        AsyncCallback cb, object extraData)
    {
      taskGrogress = "AsyncTask started at: " + DateTime.Now + ". ";

      dlgt = new AsyncTaskDelegate(ExecuteAsyncTask);
      IAsyncResult result = dlgt.BeginInvoke(cb, extraData);

      return result;
    }

    public void OnEnd(IAsyncResult ar)
    {
      taskGrogress += "AsyncTask completed at: " + DateTime.Now;
      dlgt.EndInvoke(ar);
    }

    public void OnTimeout(IAsyncResult ar)
    {
      taskGrogress += "AsyncTask failed to complete because it exceeded the AsyncTimeout parameter.";
    }
  }
}

畫面如下

image

 

AJAX 的部份,可參考 AJAX 之 PageMethod
由實驗得知,兩種實作起來,伺服器端同步的AJAX效果比較好,但伺服器端非同步的伺服器資源使用率會較高。

程式碼可由這裡下載

1 則留言:

surrounding 提到...

本人對長時間的工作編排有些不明白。

原來使用者在按submit後是會增加一項資料,然後更新頁面
若果現在除此之外,要在加資料後,背後要把相關大量資料生成報表存入資料庫(可能要幾分鐘)
怎樣做才可以不影響更新頁面的時間,背後繼續運行呢?
我想到的就是用async的方法,但只有己概念而已。
究竟應該怎樣做呢?

Share with Facebook