2013-03-14 39 views
0

我有一个页面。在该页面中,根据服务呼叫显示一些数据。以另一种操作方法开始的背景任务的访问结果

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

所以我的索引操作方法就像这样做,不要叫这个长时间的服务调用。

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

此模型正在工作

我想对此进行修改。

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

这里面临的挑战是如何在Ajax操作方法中访问Index操作方法中启动的踩点结果?

+0

你可以设置一个计时器,每隔一段时间触发一次ajax调用。 – derape 2013-03-14 07:12:14

+0

你不能使用AsyncController吗? – 2013-03-14 07:26:16

回答

2

您可以让Index操作(启动任务的那个操作)生成一个与此任务关联的唯一编号(可以是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> 

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

+0

我很高兴Darin理解我的问题。 但是,在Ajax操作方法中,无法获得在索引上启动的踩点结果。 假设在索引方法上启动的线程有一些返回值(驱逐对象列表)。 我将如何在Ajax方法中获得该结果? 如何在从Ajax操作返回之前让系统完成该线程[如果未完成]? – 2013-03-15 05:06:52

+0

@ user444569,而不是将简单的字符串值存储到缓存中,而是定义一个可以保存结果的复杂模型。最初,当任务开始时,Result属性将为null,当任务完成时,您将其设置为相应的值。您不会将其从缓存中移除。然后在AJAX处理程序中,您将能够查询缓存值并查看是否设置了Result属性。如果是,任务已经完成,并且你有结果。我在我的答案的最后部分解释了这一点。 – 2013-03-15 06:53:09