【问题标题】:How to cancel an ActionResult method that is currently running from another ActionResult method?如何取消当前从另一个 ActionResult 方法运行的 ActionResult 方法?
【发布时间】:2017-09-08 16:54:04
【问题描述】:

在我的 MVC 网站中有显示流程数据的按钮。此按钮调用 ActionResult 方法“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 });
    }

还有用于取消过程的第二个按钮。此按钮调用 ActionResult 方法“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 });
    }
  1. 当用户点击处理按钮时,数据正在处理中,需要很长时间。
  2. 我希望用户能够通过单击取消按钮来取消进程。

如何从另一个 ActionResult 方法取消当前正在运行的 ActionResult 方法?请介绍一下。

附:抱歉英语不好。

编辑 1:这是 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>

结束编辑 1

编辑2:经过我长时间的搜索。我找到了取消过程的解决方案。显示此代码

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 });
    }

下面是脚本函数

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

结束编辑 2

【问题讨论】:

  • 你能发布取消和显示按钮的 HTML 部分吗?您正在使用 ajax 调用?
  • 你不能(它们是 2 个单独的请求)
  • ProcessData & CancelProcessData 接受不同的请求(它们都被声明为ActionResult),如果第一个请求已经启动,您似乎无法从另一个方法请求中取消 HTTP 请求.
  • @praga2050 请查看问题顶部的 HTML 部分,我正在编辑它。
  • 非常感谢大家。如果没有,还有其他方法吗?请提供给我。

标签: javascript c# jquery asp.net-mvc ajax-request


【解决方案1】:

(现在,我不确定 Session 值是否在整个 Http 请求中保持不变或被更新)

这取决于您正在运行的进程类型。它不会停止任何正在运行的进程,但它可以撤消并停止进一步的处理。

在您的 javascript 中创建一个名为 processTimeStamp 的变量。注意,它的声明必须在这两个函数之外。就在调用过程数据之前,分配processTimeStamp,这将是ProcessDataCancelProcessData 方法的参数。由于该变量在全局范围内,因此将向这两个方法发送相同的值。

<script>
    var processTimeStamp;
    function ProcessData() {
        var actionUrl = '@Url.Action("ProcessData", "Home")';
        processTimeStamp = new Date().getTime().toString();

        $.ajax({
            type: "POST",
            url: actionUrl,
            data: {
              processTimeStamp: processTimeStamp 
            },
            contentType: "application/Json",
            success: function (result) {
                if (result.IsComplete) {
                    var reUrl = '@Url.Action("Index", "Home")';
                    window.location = reUrl;
                } else if (result.IsCancelComplete) {
                     alert("process was cancelled");
                }
            },
            error: function () {
                alert("Error");
            }
        });
    }

    function CancelProcessData() {
        var actionUrl = '@Url.Action("CancelProcessData", "Home")';
        $.ajax({
            type: "POST",
            url: actionUrl,
            data: {
              processTimeStamp: processTimeStamp 
            },
            contentType: "application/Json",
            success: function (result) {
            },
            error: function () {
                alert("Error");
            }
        });
    }
</script>

控制器

在您的CancelProcessData 方法中,将processTimeStamp 的值分配给Session["CancelProcessTimestamp"]。您根本无法从这里知道该过程是否被取消。

在您的ProcessData 方法中,检查processTimeStamp 是否通过,是否与每个进程之前的Session["CancelProcessTimestamp"] 相同。我的意思是你没有任何选择。 (有点像您在任务并行库中处理CancellationToken 的方式)

public ActionResult ProcessData(string processTimeStamp)
{
    bool isComplete = false;
    bool isCancelComplete = false;
    string errMessage = "";

    try
    {

        // process 1 <-- this starts immediately. So you can't stop that.

        if( Convert.ToString(Session["CancelProcessTimestamp"]) != processTimeStamp)
        {
           // process 2
        }
        else
        {
           isCancelComplete = true;
        }

        // OTHER PROCESSES

        if(Convert.ToString(Session["CancelProcessTimestamp"]) != processTimeStamp)
        {
           // update to database
           isComplete = true; // only if it completes the last process
        }
        else
        {
           // you can undo the work done in process 1, 2 etc. 
           // Like deleting an uploaded file. Or if any primary key is returned from Process 1, then delete the corresponding entry in Data base
           isCancelComplete = true;
        }
    }
    catch (Exception e)
    {
        errMessage = e.Message;
    }

    return Json(new { IsComplete = isComplete, IsCancelComplete = isCancelComplete , ErrorMessage = errMessage });
}


public ActionResult CancelProcessData(string processTimeStamp)
{
    Session["CancelProcessTimestamp"] = processTimeStamp;
    return Json(true);
}

【讨论】:

  • 我可以在我的编辑 2 中找到解决方案。请参阅。非常感谢。
  • @user2955394 有用吗?在您的编辑中,流程在哪里?
  • 请参阅我在 Edit2 中的问题,我使用长 for 循环测试过程。当单击处理按钮时,请求调用方法 ProcessData 并运行很长时间。但是当单击取消按钮时,它会调用 abort()。当 ajax 调用 abort() 时, HttpContext.Response.ClientDisconnectedToken.IsCancellationRequested 设置为 true 然后我打破循环。这对我有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-23
  • 1970-01-01
  • 1970-01-01
  • 2016-01-22
  • 1970-01-01
  • 2018-11-13
  • 1970-01-01
相关资源
最近更新 更多