0

i am calling an asmx service from my windows form application in a background worker. i want to be able to cancel/stop the call once a button is pressed.

i am currently performing the following:

backgroundWorker1 = new BackgroundWorker();
            backgroundWorker1.WorkerSupportsCancellation = true;
            backgroundWorker1.WorkerReportsProgress = true;
            backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(backgroundWorker1_DoWork);
            backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
            backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);



public void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            GlobalVariables.worker = sender as BackgroundWorker;
            try
            {
                if (GlobalVariables.worker.CancellationPending == true)
                {
                    e.Cancel = true;
                    return;
                }
                else
                {
                    e.Result = CallServer(ServerName, ActionName); // call on a web method in the referenced service 

                }
            }
            catch (Exception ee)
            {
                GlobalFunctions.ShowError(ee);
            }
        }



private void button1_Click(object sender, EventArgs e) //button to cancel the call
        {
            if (GlobalVariables.worker.IsBusy == true)
            {
                //GlobalVariables.worker.thre;
                GlobalVariables.worker.CancelAsync();
                GlobalVariables.worker.Dispose();

            }
            //GlobalVariables.worker.CancelAsync();
            Form1.f.Enabled = true;
            Form1.f.progressBar1.Text = "Done!";
            Form1.f.progressBar1.Visible = false;
            Form1.f.textBox1.Visible = true;
            Close();
        }

the following doesnt seem to work because when i press on cancel, the web method called in the service reference is not stopped and still returns data

Rashad.Z
  • 2,494
  • 2
  • 27
  • 58
  • The problem is you're only testing for cancellation before making the call.. so, pretty much ms after you hit dowork, its too late.. if callserver takes a very long time, it will always wait for completion.. – BugFinder Jul 18 '16 at 11:11
  • your right. but is there a way to do that during execution or its a dead end? – Rashad.Z Jul 18 '16 at 11:13
  • Id not assign e.result direct, and check for cancel after, and return e.cancel if it was – BugFinder Jul 18 '16 at 11:24

2 Answers2

1

You can make client react immediately to the Abort button by using a Task and a CancellationToken. The client will do its best to abort the call, but the server will continue execution of the call unless it does something special about that.

Here is the code of the client side:

public partial class Form1 : Form
{
    private CancellationTokenSource _cancellationTokenSource;
    private WebService1SoapClient _client;

    public Form1()
    {
        InitializeComponent();
        btnAbort.Enabled = false;
    }

    private void btnCall_Click(object sender, EventArgs e)
    {
        btnCall.Enabled = false;
        btnAbort.Enabled = true;
        lblStatus.Text = "CALLING SERVER...";

        _cancellationTokenSource = new CancellationTokenSource();
        _cancellationTokenSource.Token.Register(() => backgroundWorker1.CancelAsync());

        backgroundWorker1.RunWorkerAsync();
    }

    private void btnAbort_Click(object sender, EventArgs e)
    {
        if (_cancellationTokenSource != null)
        {
            _cancellationTokenSource.Cancel();
        }
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        if (backgroundWorker1.CancellationPending)
        {
            e.Cancel = true;
            return;

        }
        try
        {
            _client = new WebService1SoapClient();
            var call = CallServerAsync("ServerName", "ActionName");
            call.Wait(_cancellationTokenSource.Token);
            e.Result = call.Result;
        }
        catch (TaskCanceledException)
        {
            e.Cancel = true;
            _client.Abort();
        }
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        btnCall.Enabled = true;
        btnAbort.Enabled = false;
        lblStatus.Text = (e.Error != null ? "CALL FAILED: " + e.Error.Message : "CALL COMPLETED!");
    }

    private async Task<string> CallServerAsync(string serverName, string actionName)
    {
        var response = await _client.HelloWorldAsync();
        return response.Body.HelloWorldResult;
    }
}
felix-b
  • 8,178
  • 1
  • 26
  • 36
0

thanks to @felix-b answer , i did the following:

 public void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
 {
      GlobalVariables.worker = sender as BackgroundWorker;
      try
      {
        if (GlobalVariables.worker.CancellationPending == true)
        {
             e.Cancel = true;
             return;
        }
        else
        {
            Object callResponse = CallServer(ServerName, ActionName);
            if (GlobalVariables.worker.CancellationPending == true)
            {
                e.Cancel = true;
                return;
             }
             else
             {
                 e.Result = callResponse;
             }

          }
         }
         catch (Exception ee)
         {
             e.Cancel = true;
             if (ee.GetType().IsAssignableFrom(typeof(System.ServiceModel.CommunicationObjectAbortedException)))
             {
                MessageBox.Show("The Request Was Cancelled");
             }
             else
             {
                GlobalFunctions.ShowError(ee);
             }

          }
  }

public void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled)
    {}
    else
    {
    //continue
    }
}

private void button1_Click(object sender, EventArgs e)
{
   if (GlobalVariables.worker.IsBusy == true)
   {

       server.abort(); //service reference
       GlobalVariables.worker.CancelAsync();
        GlobalVariables.worker.Dispose();
    }
}
Rashad.Z
  • 2,494
  • 2
  • 27
  • 58