Reputation: 7979
I have a page. In that page some data is shown based on a service call.
This service call may take more than one minute.
So my Index action method have made like that don’t call this long service call.
But this service call is called though an Ajax call on page load.
This model is working
I would like to have a modification to this.
I would like to call this service call in different thread using Task.Factory.StartNew
in index action itself. Let that thread be working in background even though the view is returned. And a separate Ajax call I should be able to get the result of the service thread.
The challenge here is how I can access the result of the tread started in Index action method in an Ajax action method?
Upvotes: 0
Views: 143
Reputation: 1038830
You could have the Index action (the one that is starting the task) generate an unique number that will be associated to this task (could be a guid) and store an entry into the cache associated to this number. Then return the number to the view.
The task will then be running silently in the background and could update the entry you stored into the cache (with information such as the progression of the task or if you cannot implement this simply indicate whether the task has finished or not). Once the task finishes, remove the entry from the cache.
The view itself could send AJAX requests at regular intervals to another controller action and pass the id of the task. The action will look for the corresponding entry in the cache using this key and return to the view information about the running task. The view itself could then update the UI.
Let's have an example, shall we?
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);
}
and then you could have another controller action that will be called by the view with an AJAX call to notify the progression of the task:
[HttpPost]
public ActionResult TaskProgress(Guid taskId)
{
var isTaskRunning = MemoryCache.Default.Contains(taskId.ToString());
return Json(new { status = isTaskRunning });
}
and finally you could have the Index view:
@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>
Of course this is just an oversimplified example. In a real world scenario you will have view models, use a complex model for the cache instead of just a simple string where you could hold information about the task and the result of the task if this task need to yield some result after it has finished executing, ...
Upvotes: 2