Jason Edel-Brock Jason Edel-Brock - 2 months ago 7x
Vb.net Question

VB.Net BackgroundWorker and AsyncCancel Not Working Correctly

Hello again StackOverflow Community!

I am having some issues with a BackgroundWorker and AsyncCancel. The BackgroundWorker simply sends a email but I would like to be able to report when the task or email has been sent and as well be able to cancel the task or email from being sent.

The problem is after hitting cancel, it continues and then reports a error, not canceled.

Any help is greatly appreciated!

Thank you!

Here is my complete code minus comments and imports:

Private Sub Sendmail_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

StatusLabel.Text &= "Idle"

End Sub

Private Sub SendmailBackgroundWorker_DoWork(sender As Object, e As DoWorkEventArgs) Handles SendmailBackgroundWorker.DoWork


Dim Smtp As New SmtpClient()
Dim Email As New MailMessage()

Smtp.Port = 25
Smtp.Host = "mail.server.com"

Smtp.EnableSsl = False
Smtp.UseDefaultCredentials = False

Smtp.Credentials = New Net.NetworkCredential("user@server.com", "password")

Email = New MailMessage()
Email.From = New MailAddress(FromTextBox.Text)
Email.Subject = SubjectTextBox.Text
Email.IsBodyHtml = False
Email.Body = BodyTextBox.Text


Catch ex As Exception

MsgBox("Sendmail Error!" & vbNewLine & vbNewLine & ex.ToString)

End Try

If SendmailBackgroundWorker.CancellationPending Then

StatusLabel.Text = "Canceling"
e.Cancel = True

End If

End Sub

Private Sub SendmailBackgroundWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles SendmailBackgroundWorker.RunWorkerCompleted

StatusLabel.Text = "Status: "

If (e.Error IsNot Nothing) Then

StatusLabel.Text &= "Worker Error!" & vbNewLine & vbNewLine & e.Error.Message

ElseIf e.Cancelled Then

StatusLabel.Text &= "Canceled!"


StatusLabel.Text &= "Sent!"

End If

SendButton.Enabled = True
CancelButton.Enabled = False

End Sub

Private Sub SendButton_Click(sender As Object, e As EventArgs) Handles SendButton.Click

StatusLabel.Text = "Status: "

SendButton.Enabled = False
CancelButton.Enabled = True

SendmailBackgroundWorker.WorkerSupportsCancellation = True
SendmailBackgroundWorker.WorkerReportsProgress = True

StatusLabel.Text &= "Sending..."


End Sub

Private Sub CancelButton_Click(sender As Object, e As EventArgs) Handles CancelButton.Click

CancelButton.Enabled = False

End Sub


That is working exactly as it should. The problem is that you haven't read up properly on how it works. Calling CancelAsync (NOT AsyncCancel) on a BackgroundWorker does NOT cancel anything. All it does is set a flag on the BackgroundWorker object. It's up to you to test that flag in your DoWork event handler and, if it's set, it's then for you to stop the work. In your current code, you're not testing that flag until after the email has been sent so of course the email gets sent whether you try to cancel or not.

You are overestimating what cancelling a BackgroundWorker can accomplish. The BackgroundWorker itself doesn't know what you're doing in the DoWork event handler so it's not going to simply abort it. It gives you the chance to terminate the task at an appropriate point in the code. If there is no appropriate point then you can't cancel anything.

In your case, once you call Send on your SmtpClient, you can't do anything until that synchronous method returns, so you can't cancel it. What you should be doing is not using a BackgroundWorker at all but rather the asynchronous functionality built into the SmtpClient class. It has a SendAsync method and a SendAsyncCancel method, so you can let it handle the multithreading for you.