インデックス アクション (タスクを開始するアクション) で、このタスクに関連付けられる一意の番号 (GUID の可能性があります) を生成し、この番号に関連付けられたキャッシュにエントリを格納することができます。次に、番号をビューに返します。
タスクはバックグラウンドで静かに実行され、キャッシュに保存したエントリを更新できます (タスクの進行状況などの情報を使用するか、これを実装できない場合は、タスクが終了したかどうかを示すだけです)。タスクが完了したら、キャッシュからエントリを削除します。
ビュー自体は、定期的に AJAX リクエストを別のコントローラー アクションに送信し、タスクの ID を渡すことができます。アクションは、このキーを使用してキャッシュ内の対応するエントリを探し、実行中のタスクに関するビュー情報に戻ります。その後、ビュー自体が UI を更新できます。
例を挙げましょう。
public ActionResult Index()
{
var taskId = Guid.NewGuid().ToString();
var policy = new CacheItemPolicy
{
Priority = CacheItemPriority.NotRemovable,
// Adjust the value to some maximum amount of time that your task might run
AbsoluteExpiration = DateTime.Now.AddHours(1)
};
MemoryCache.Default.Set(taskId, "running", policy);
Task.Factory.StartNew(key =>
{
// simulate a long running task
Thread.Sleep(10000);
// the task has finished executing => we could now remove the entry from the cache.
MemoryCache.Default.Remove((string)key);
}, taskId);
return View((object)taskId);
}
次に、タスクの進行状況を通知するために、AJAX 呼び出しを使用してビューによって呼び出される別のコントローラー アクションを作成できます。
[HttpPost]
public ActionResult TaskProgress(Guid taskId)
{
var isTaskRunning = MemoryCache.Default.Contains(taskId.ToString());
return Json(new { status = isTaskRunning });
}
最後に、Index ビューを使用できます。
@model string
<div id="status">Task with id @Model has been started and running</div>
<script type="text/javascript">
// start continuous polling at 1s intervals
window.setInterval(function() {
$.ajax({
url: '@Url.Action("TaskProgress", new { taskId = Model })',
type: 'GET',
cache: false,
success: function(result) {
if (!result.status) {
// the task has finished executing => let's notify the user
$('#status').html('The task has finished executing');
}
}
});
}, 1000);
</script>
もちろん、これは単純化しすぎた例にすぎません。実際のシナリオでは、ビュー モデルがあり、このタスクが終了後に結果を生成する必要がある場合、タスクとタスクの結果に関する情報を保持できる単純な文字列ではなく、キャッシュに複雑なモデルを使用します。実行中、...