In my MVC website has show button for process data. This button call to the ActionResult method "ProcessData".
public ActionResult ProcessData()
{
bool isComplete = false;
string errMessage = "";
try
{
//Calculate something that take long time.
isComplete = true;
}
catch (Exception e)
{
errMessage = e.Message;
}
return Json(new { IsComplete = isComplete, ErrorMessage = errMessage });
}
And the second button for cancel process. This button call to the ActionResult method "CancelProcessData".
public ActionResult CancelProcessData()
{
bool isCancelComplete = false;
string errMessage = "";
try
{
//Cancel Process Data
isCancelComplete = true;
}
catch (Exception e)
{
errMessage = e.Message;
}
return Json(new { IsCancelComplete = isCancelComplete , ErrorMessage = errMessage });
}
- When user clicked at the process button, the data is processing and takes a long time.
- I want the user to be able to cancel a process by click at the cancel button.
How to cancel an ActionResult method that is currently running from another ActionResult method? Please introduce me.
P.S. Sorry for bad english skill.
Edit 1: this is code in ProcessData.cshtml
<script>
function ProcessData() {
var actionUrl = '@Url.Action("ProcessData", "Home")';
$.ajax({
type: "POST",
url: actionUrl,
contentType: "application/Json",
success: function (result) {
if (result.IsComplete) {
var reUrl = '@Url.Action("Index", "Home")';
window.location = reUrl;
}
},
error: function () {
alert("Error");
}
});
}
function CancelProcessData() {
var actionUrl = '@Url.Action("CancelProcessData", "Home")';
$.ajax({
type: "POST",
url: actionUrl,
contentType: "application/Json",
success: function (result) {
if (result.IsComplete) {
alert("Cancel Complete");
}
},
error: function () {
alert("Error");
}
});
}
</script>
<button onclick="ProcessData();">Process Data</button>
<button onclick="CancelProcessData();">Cancel Process Data</button>
End edit 1
Edit 2:After I search for long time. I find a solution for cancel process. this code is shown
public async System.Threading.Tasks.Task<ActionResult> ProcessData()
{
bool isComplete = false;
bool isCancel = false;
string errMessage = "";
try
{
await System.Threading.Tasks.Task.Run(() => {
for (int i = 0;i< Int32.MaxValue; i++)
{
if (HttpContext.Response.ClientDisconnectedToken.IsCancellationRequested)
{
isCancel = true;
break;
}
}
});
isComplete = true;
}
catch (Exception e)
{
errMessage = e.Message;
}
return Json(new { IsComplete = isComplete, ErrorMessage = errMessage, IsCancel = isCancel });
}
this below is script function
<script>
var ajaxProcessDatarequest;
function ProcessData() {
var actionUrl = '@Url.Action("ProcessData", "Home")';
ajaxProcessDatarequest = $.ajax({
type: "POST",
url: actionUrl,
contentType: "application/Json",
success: function (result) {
if (result.IsComplete) {
if (!result.IsCancel) {
var reUrl = '@Url.Action("Index", "Home")';
window.location = reUrl;
}
}
},
error: function () {
alert("Error");
}
});
}
function CancelProcessData() {
ajaxProcessDatarequest.abort();
}
</script>
End edit 2
(Now, I'm not sure if a Session value remains same through out an Http request or gets updated)
This depends on what kind of process you're running. It won't stop any running processes but it can undo and stop the further processing.
In your javascript create a variable called
processTimeStamp
. Notice, it's declaration must be outside both of these functions. Just before calling the process data, assign theprocessTimeStamp
and this will be the parameter to bothProcessData
andCancelProcessData
methods. Since, the variable is in global scope, the same value will be sent to both of these methods.Controller:
In your
CancelProcessData
method, assign the value ofprocessTimeStamp
toSession["CancelProcessTimestamp"]
. You simply can't know whether the process is cancelled or not from here.In your
ProcessData
method, check if theprocessTimeStamp
passed, is same as theSession["CancelProcessTimestamp"]
before every process. I mean you don't have any option. (Kind of like how you'd handleCancellationToken
in the Task Parallel Library)