2010-05-28 61 views
40

我一直試圖在我的項目中創建一個控制器,以實現相當複雜的報表。因此,他們可能需要相當長的時間,進度條肯定會幫助用戶知道事情正在進行。該報告將通過AJAX請求啓動,其想法是定期的JSON請求將獲得狀態並更新進度欄。需要一個帶有用戶反饋的ASP.NET MVC長時間運行過程

我一直在試驗AsyncController,因爲這似乎是一個很好的方式來運行長進程而不捆綁資源,但它似乎沒有給我任何檢查進度的方式(似乎阻止進一步的JSON請求,我還沒有發現爲什麼)。之後,我嘗試着在控制器上的靜態變量中存儲進度,並從中讀取狀態 - 但說實話,這似乎有點哈克!

感謝您接受所有建議!

+0

報告的輸出是什麼(screen,pdf?) – 2010-05-28 07:36:23

+0

屏幕 - 無論是HTML還是JSON對象,對我而言都不重要(只要我得到迴應,我就可以解析和顯示)。 – Jason 2010-05-28 09:31:34

+1

這不是ASP.Net SignalR的絕佳選擇嗎?我知道這是一條古老的線索,但現在我處於類似的情況。 – 2013-04-09 06:21:34

回答

43

這裏有一個示例中,我寫道,你可以嘗試:

控制器:

public class HomeController : AsyncController 
{ 
    public ActionResult Index() 
    { 
     return View(); 
    } 

    public void SomeTaskAsync(int id) 
    { 
     AsyncManager.OutstandingOperations.Increment(); 
     Task.Factory.StartNew(taskId => 
     { 
      for (int i = 0; i < 100; i++) 
      { 
       Thread.Sleep(200); 
       HttpContext.Application["task" + taskId] = i; 
      } 
      var result = "result"; 
      AsyncManager.OutstandingOperations.Decrement(); 
      AsyncManager.Parameters["result"] = result; 
      return result; 
     }, id); 
    } 

    public ActionResult SomeTaskCompleted(string result) 
    { 
     return Content(result, "text/plain"); 
    } 

    public ActionResult SomeTaskProgress(int id) 
    { 
     return Json(new 
     { 
      Progress = HttpContext.Application["task" + id] 
     }, JsonRequestBehavior.AllowGet); 
    } 
} 

查看:

<script type="text/javascript"> 
$(function() { 
    var taskId = 543; 
    $.get('/home/sometask', { id: taskId }, function (result) { 
     window.clearInterval(intervalId); 
     $('#result').html(result); 
    }); 

    var intervalId = window.setInterval(function() { 
     $.getJSON('/home/sometaskprogress', { id: taskId }, function (json) { 
      $('#progress').html(json.Progress + '%'); 
     }); 
    }, 5000); 
}); 
</script> 

<div id="progress"></div> 
<div id="result"></div> 

的想法是啓動一個異步操作,將使用報告進展情況HttpContext.Application這意味着每個任務必須具有唯一的ID。然後在客戶端,我們啓動任務,然後發送多個AJAX請求(每5秒)來更新進度。您可以調整參數以適應您的情況。進一步的改進是增加異常處理。

+0

感謝Darin,我嘗試了你的代碼,但仍然讓所有的請求都'相互支持'。在今天早上花了很長時間尋找答案之後,我現在開始認爲這可能與Session不相關,不允許同時發出多個請求,從而強制請求同步。 我不得不做的一個改變是你使用Task.Factory,因爲我目前在.NET 3中工作,而不是4.你認爲Task.Factory會解決會話鎖定問題嗎? – Jason 2010-05-28 11:13:53

+1

此外,我剛剛得到您的代碼運行,並通過刪除我的控制器中引用會話的任何代碼,所以這顯然是我的問題。不幸的是,我的控制器都需要我在Session中持有的各種數據(並且在一個BaseController中檢索,他們都在擴展),所以我看不到任何簡單的解決方法。 – Jason 2010-05-28 11:18:59

+0

會話在異步操作中並不總是可用。 – 2010-05-28 11:32:09

2

這個問題已經回答了4.5年,我們有一個庫可以使這個任務變得更容易:SignalR。不需要使用共享狀態(這很糟糕,因爲它可能導致意外的結果),只需使用HubContext類連接到將消息發送到客戶端的Hub即可。

首先,我們像往常一樣設置SignalR連接(請參閱,例如here),但我們的Hub上不需要任何服務器端方法。然後,我們對我們的端點/控制器/無論什麼進行AJAX調用,並傳遞連接ID,我們像往常一樣獲得:var connectionId = $.connection.hub.id;。在服務器端,你可以在不同的線程上啓動你的進程,並向客戶端返回200 OK。這一過程將知道的ConnectionId,以便它可以將消息發送回客戶端,就像這樣:

GlobalHost.ConnectionManager.GetHubContext<LogHub>() 
           .Clients.Client(connectionId) 
           .log(message); 

這裏,log是你想從服務器調用客戶端的方法,因此它應該被定義就像你通常做SignalR:

$.connection.logHub.client.log = function(message){...}; 

更多細節在我的博客文章here

+5

當然,在上面的問題上,大約2年前發佈了有關SignalR的評論。你真的不應該只是發佈一個鏈接到你的博客,因爲這是邊緣垃圾和只有鏈接的答案是皺眉。 – 2015-01-15 05:46:03

+0

抱歉,不代表垃圾郵件。答案已更新。 – ulu 2015-01-20 07:32:13

+0

這似乎是一個很好的答案。是否有人使用SignalR而不是像Darrin的答案那樣進行輪詢? – Jess 2017-07-24 14:32:16

0

如果你有你的Web服務器計算機的訪問作爲一個選擇,你可以創建Windows服務或簡單的控制檯應用程序執行LON g運行工作。您的Web應用程序應該向db添加一條記錄以指示操作應該開始,並且定期檢查db中新記錄的Windows服務應該開始執行任務並向db報告進度。 您的網絡應用程序可以使用ajax請求來檢查進度並向用戶顯示。

我用這個方法來實現asp.net mvc應用程序的excel報告。 該報告由windows服務創建,該服務在機器上運行,並不斷檢查報告表中的新記錄,並在發現新記錄時開始創建報告並通過更新記錄字段指示進度。 Asp.net mvc應用程序只是在數據庫中添加新的報告記錄和跟蹤進度,直到它完成,然後提供一個鏈接,以準備下載文件。

相關問題