Cancel current synchronous request processing

2019-08-21 10:31发布

问题:

I am trying to cancel current request made by user. Web Forms Web App have export to excel feature. If it takes long time to generate excel report user can cancel the request.

Once the cancel button is clicked the server should stop processing to save precious bandwidth.

I have found two solutions as listed below.

First Solution:

Prevent further code from executing by jumping straight to the Application_EndRequest event.

    protected void btnCancel_Click(object sender, EventArgs e)
    {

        if (Response.IsClientConnected)
        {

            HttpContext.Current.ApplicationInstance.CompleteRequest();

        }


    }

Second Solution: (Using Task Parallel Library - TPL)

   CancellationTokenSource tokenSource = new CancellationTokenSource();


    protected void Page_Load(object sender, EventArgs e)
    {

    }


    protected void btnExportExcel_Click(object sender, EventArgs e)
    {
        CancellationToken cToken = tokenSource.Token;

        Task.Factory.StartNew(() =>
        {
                // do some heavy work here

                GenerateReport(sender, cToken);

                if (cToken.IsCancellationRequested)
                {

                // another thread decided to cancel
                  return;

                }

        }, cToken);

        // to register a delegate for a callback when a
        // cancellation request is made

        cToken.Register(() => cancelNotification());

    }

    private void GenerateReport(object sender, CancellationToken ct)
    {

    var students = _context.Students.ToList();

    var courses = _context.Courses.ToList();

    var teachers = _context.Teachers.ToList();

    // Todo: Use above data to Generate Excel Report

    // Just to Simulate Export to excel

        Thread.Sleep(7000);

    }


    protected void btnCancel_Click(object sender, EventArgs e)
    {

            tokenSource.Cancel();

    }


    private static void cancelNotification()
    {
        // Why never called ?

    }

In second solution I have used Task Parallel Library (TPL) and registered a callback method on cancellation using CancellationToken. I have few questions:

  1. But the callback method is never called when I click cancel button, may I know why ?

  2. Using Entity framework can I cancel all 3 .ToList() statements before it hits the database to fetch the data.

  3. Also may I know is it best option to go with TPL ?

Any help would be appreciated.

回答1:

I think you have to register the callbackfunction befor you start the Task. Your Code have to look something like this.

In you Page_Load method you have to save the CancellationTokenSource in the User session.

public partial class Contact : Page
{
    CancellationTokenSource tokenSource = new CancellationTokenSource();


    protected void Page_Load(object sender, EventArgs e)
    {
        if (HttpContext.Current.Session["Cart"] != null)
        {
            tokenSource = HttpContext.Current.Session["Cart"] as CancellationTokenSource;
        }
        else
        {
            HttpContext.Current.Session.Add("Cart", new CancellationTokenSource());
            tokenSource = HttpContext.Current.Session["Cart"] as CancellationTokenSource;
        }
    }


    protected void btnExportExcel_Click(object sender, EventArgs e)
    {
        CancellationToken cToken = tokenSource.Token;
        cToken.Register(() => cancelNotification());

        Task.Factory.StartNew(() =>
        {
        // do some heavy work here

        GenerateReport(sender, cToken);

            if (cToken.IsCancellationRequested)
            {

            // another thread decided to cancel
            return;

            }

        }, cToken);
    }

    private void GenerateReport(object sender, CancellationToken ct)
    {

        var students = _context.Students.ToList();

        var courses = _context.Courses.ToList();

        var teachers = _context.Teachers.ToList();

        // Todo: Use above data to Generate Excel Report

        // Just to Simulate Export to excel

        Thread.Sleep(7000);

    }


    protected void btnCancel_Click(object sender, EventArgs e)
    {

        tokenSource.Cancel();

    }


    private static void cancelNotification()
    {
        // Why never called ?

    }
}

Your second question.

You can load the list async. With the Method ToListAsync() and there you can give your canalactiontoken in it.

Microsoft Dokumentation

I hope this help you?