Cancel a task that running on thread in ASP.NET MVC using C#

977 Views Asked by At

How do i run this task in background and my other web stuff (Server API's) should work? and also cancelable on any point. Because my server is capable of run heavy operations and multi thread.

C#

[HttpPost]
[AsyncTimeout(30 * 60 * 1000)]
//ConnectionId show importing data on UI as progress bar using SignalRProgress.
//Path import file path for import some bulk data in background.
//cancellationToken to cancel task when user need.
public async Task<ActionResult> LongRunningTask(string ConnectionId, string Path, System.Threading.CancellationToken cancellationToken)
{
    CancellationToken disconnectedToken = Response.ClientDisconnectedToken;
    var source = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, disconnectedToken);

    string someResponse = "Empty";

    await Task.Run(() =>
    {
        foreach (var item in spec)
        {
            i++;
            try
            {
                if (source != null && source.IsCancellationRequested)
                {
                    //abort or cancel this thread and 

                    //custome method that add progress to an hub context
                    //update UI for task cancelation with how much importing is done
                    Utility.SignalRProgressEvent.SendProgress(ConnectionId, Message, DonePercentage);
                    break;
                }
                
                importedDetails = service.ImportData(item, source.Token);
            }
            catch (CustomException ex)
            {
                someResponse += what is the validation issue in which record;
            }
            catch (JsonSerializationException ex)
            {
                someResponse += which attribute have serialization error;
            }
            catch (Exception ex)
            {
                throw ex;
            }

            //update UI for how much import is done
            someResponse += information of errors/importedid/validaiton issue;
            Utility.SignalRProgressEvent.SendProgress(ConnectionId, Message, DonePercentage);
        }
    }, source.Token);

    return Json(someResponse, JsonRequestBehavior.AllowGet);
}

Javascript

/*Update progress bar*/
function ProgressBarModal(showHide) {
    if (showHide === 'show') {
        $('#mod-progress').modal('show');
        if (arguments.length >= 2) {
            var percentage = "0";
            if (arguments.length >= 3) {
                percentage = arguments[2]
                $('#ProgressMessage').width(percentage);
                if (percentage == "100%") {
                    ProgressBarModal();
                }
            }
            $('#progressBarTextMessage').text(arguments[1] + " " + percentage);
            window.progressBarActive = true;
        }
    } else {
        $('#mod-progress').modal('hide');
        window.progressBarActive = false;
    }
}

var xhr = undefined;

/*start  import*/
function StartImport() {
    xhr = $.ajax({
            type: 'POST',
            url: "@Url.Action("Import", "BulkOps")",
            data: data,
            async: true, //I want run progress bar using JS
            beforeSend: function () {
                ProgressBarModal('show');
            },
            success: function (data) {
                //import done
            },
            error: function (err) {
                //handle import failing 
            },
            complete: function (data) {
                //share import report if possible
            }
        });
});

/*Abort running import*/
function AbortImport() {
    xhr.abort("Task aborted by the user.");
});

Is there any possible solution to abort the same task? but server should not stuck on that same long running process.

Thanks in advance.

Please ignore my past question below here. I drop out the thread idea.

I am trying to cancel my long running task in between progress, this is possible when we work with single thread, but i want to run any long running in a background thread so i can run other action in my web.

Is this possible to cancel or abort that thread that running in background?

[HttpPost] [AsyncTimeout(30 * 60 * 1000)] //ConnectionId show
importing data on UI as progress bar using SignalRProgress. //Path
import file path for import some bulk data in background.
//cancellationToken to cancel task when user need. public ActionResult
LongRunningTask(string ConnectionId, string Path,
System.Threading.CancellationToken cancellationToken) {
    CancellationToken disconnectedToken = Response.ClientDisconnectedToken;
    var source = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken,
disconnectedToken);

    string someResponse = "Empty";
    Thread t = new Thread(() => {
        if (source != null && source.IsCancellationRequested || string.IsNullOrWhiteSpace(ConnectionId))
        {
            //abort or cancel this thread and 

            //custome method that add progress to an hub context
            //update UI for task cancelation with how much importing is done
            Utility.SignalRProgressEvent.SendProgress(ConnectionId, Message, DonePercentage);
        }

        //update UI for how much import is done
        someResponse += information of errors/importedid/validaiton issue;
        Utility.SignalRProgressEvent.SendProgress(ConnectionId, Message, DonePercentage);
    });

    t.Start();

    //How do i wait here with main thread until above thread complete.
    return Json(someResponse, JsonRequestBehavior.AllowGet); } 

P.S. 1 change above thread with task then my complete server stuck until task complete.

P.S. 2 Make above thread as background then main thread will start that thread and complete this ajax call. Then i am not able to cancel the task.

I need a solution that allow me to run that importing from web with progress bar and should be cancelable on any point, also any other mvc action should not much affected by this action. Because my server is capable of run heavy operations and multi thread.

1

There are 1 best solutions below

2
On

There are a few options. This mostly assumes you are using a task, as you should be doing for background operations.

Cooperative cancelling

I.e. whatever task you are running needs to frequently check the cancellation token and abort processing when it is canceled. This assumes that any time consuming external calls also accepts a cancellation token.

Leave the task running but disregard the result

In some cases it is feasible to simply close the progress dialog and let the task live on in the background, disregarding any result. This assumes that the task will eventually complete, and that doing so will have no side effects.

Use thread abort

There is a Thread.Abort(). But there are very good reasons not to use thread abort. It is also removed in .Net core.

Move the operation to a separate process

This should let you shutdown the process, and avoid some of the pitfalls with Thread.Abort. This is a rather cumbersome solution, but might be appropriate for very long running operations.