I am trying to accurately learn the status of Tasks that are kicked off by a QueueBackgroundWorkerItem thread. I can access the Task object and add them to a List of my TaskModels, and send that list object to my View.
My view only ever shows one one Task status, no matter how many times I click the QueueWorkItem link, and start a new task. I'd like to figure out a couple of things:
I am hoping someone has done something similar and can help with this. Thanks! -Jason
EDIT: The core requirements of this setup are:
CONTROLLER:
List<TaskModel> taskModelList = new List<TaskModel>();
public ActionResult QueueWorkItem()
{
Task task;
ViewBag.Message = "State: ";
String printPath = @"C:\Work\QueueBackgroundWorkerItemPractice\QueueBackgroundWorkerItemPractice\WorkerPrintFile" + DateTime.Now.ToLongTimeString().ToString().Replace(":", "_") + ".txt";
System.Web.Hosting.HostingEnvironment.QueueBackgroundWorkItem(cancellationToken =>
{
task = Task.Run(() =>
{
string filePath = printPath;
string text = "File line ";
if (!System.IO.File.Exists(filePath))
{
using (var stream = System.IO.File.Create(filePath)) { }
}
TextWriter tw = new StreamWriter(printPath);
for (int i = 0; i < 400; i++)
{
text = "Line " + i;
tw.WriteLine(text);
Thread.Sleep(200);
}
tw.Close();
});
var c = task.ContinueWith((antecedent) =>
{
taskModelList.Add(new TaskModel(task));
});
});
return View(taskModelList);
}
VIEW:
@model List<QueueBackgroundWorkerItemPractice.Models.TaskModel>
@{
ViewBag.Title = "Queue Background Worker";
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message<span id="modelClass"></span></h3>
<p>Use this area to provide additional information.</p>
@{
<ul>
@foreach (var taskModel in Model)
{
<li>@taskModel.Status</li>
}
</ul>
}
EDIT, solution:
Following Raffaeu's advice, and the following compromises, I was able to find it as such:
I wanted to be able to leverage the Task ID to instantiate the task later from the ID. That proved to involve more overhead than necessary.
Instead I found the feature Task.CompletedTask
(available in .NET 4.6 and up). This, used in async, allowed me to get the status of the Task when it is complete. Voila. Thanks to everyone for your suggestions.
The best part - this long-running task will complete whether I close the browser...or stop IIS. Miraculous.
public ActionResult QueueWorkItem()
{
System.Web.Hosting.HostingEnvironment.QueueBackgroundWorkItem(cancellationToken =>
{
task = Task.Run(async () =>
{
String printPath = @"C:...";
string filePath = printPath;
string text = "File line ";
if (!System.IO.File.Exists(filePath))
{
using (var stream = System.IO.File.Create(filePath)) { }
}
TextWriter tw = new StreamWriter(printPath);
for (int i = 0; i < 400; i++)
{
text = "Line " + i;
tw.WriteLine(text);
Thread.Sleep(200);
}
tw.Close();
await Task.CompletedTask;
});
var c = task.ContinueWith((antecedent) =>
{
taskID = task.Id;
status = task.Status.ToString();
try
{
string connString = WebConfigurationManager.ConnectionStrings["TaskContext"].ToString();
sqlCommand.CommandText = "INSERT INTO dbo.TaskTable (TaskId, Status) VALUES (" + taskID + ", '" + status + "')";
conn.ConnectionString = connString;
sqlCommand.Connection = conn;
conn.Open();
sqlCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
String info = ex.Message + ex.ToString() + ex.StackTrace;
throw new Exception("SQL Issue" + info);
}
finally
{
if (conn != null)
{
conn.Close();
conn = null;
}
sqlCommand = null;
}
});
});
return View();
}
I think you are missing a point here.
When you use MVC you are in a complete "stateless" situation where the async Task is submit and executed by a different Thread, so you loose control of it. The only way that you have to "get notified" about the change of a task is to get an "event" from that task. An event will inform you about the "Status Changed". The Task class does not raise events but has the ContinueWith method. The proper way would be to:
Task
and store its Status
somewhere (DB, text file, session)ContinueWith
to upload the status of the Task
in your data storeDatastore
to get an update version of the Status
of all queued TasksI think in this thread they tried to achieve the same: How to track if an async/awaitable task is running
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With