在另一个操作方法中启动后台任务的访问结果

时间:2013-03-14 07:04:53

标签: c# ajax asp.net-mvc multithreading

我有一个页面。在该页面中,一些数据基于服务呼叫显示。

此服务电话可能需要一分钟以上。

所以我的索引操作方法就是不要调用这个长时间的服务调用。

但是,通过页面加载时的Ajax调用来调用此服务调用。

这个模型正在运作

我想对此进行修改。

我想在索引操作本身使用Task.Factory.StartNew在不同的线程中调用此服务调用。即使返回视图,也让该线程在后台工作。我应该能够获得服务线程的结果。单独的Ajax调用。

这里的挑战是如何在Ajax操作方法中访问Index action方法中启动的步骤的结果?

1 个答案:

答案 0 :(得分:2)

您可以使用索引操作(启动任务的操作)生成将与此任务关联的唯一编号(可能是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 });
}

最后你可以拥有索引视图:

@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>

当然这只是一个过于简单的例子。在现实世界中,您将拥有视图模型,使用复杂模型进行缓存,而不仅仅是一个简单的字符串,如果此任务需要在完成后产生一些结果,您可以保存有关任务和任务结果的信息执行,......