Translating and understanding what this code block does in c#, adn see if I translated it right for me to use.
-
I'm having problems with sending email using CBeyond from all of my programs in VB. So I decided to change my send function to SendAsync, and Async, and just send each message 1 at at a time and wait for the results so it can be logged when done. (Thus the SQLite Question earlier) So I thought this would be pretty easy, just change SmtpClient.Send(mailMessage) to smtpClient.SendAsync(mailMessage, cancelToken), but I guess now I need to add a callback. So I got some ideas from this link, and used some of the concepts. The part I don't understand is calling the function, and setting the Public Event for the callback. c# - Send email when using SmtpClient - Stack Overflow[^] I c#, the code is this, but I have no clue what it is, it's beyond my c# skills.
var sender = new EmailSender();
sender.SendEmailCompleted += (o, eventArgs)
=> Console.WriteLine(eventArgs.RetryCount);sender.SendEmailAsync(new MailMessage(), 5);
And I translated it using CodeTranslator CodeTranslator: Code Translation From VB.NET I'm looking at it and I have no clue what it is, I only recognize the first and last lines.
Dim sender As var = New EmailSender
sender.SendEmailCompleted = (sender.SendEmailCompleted + o)
,eventArgs
Unknown=GreaterConsole.WriteLine(eventArgs.RetryCount)
sender.SendEmailAsync(New MailMessage, 5)This is what I wrote from the C# example in the web page link. I'm pretty sure I got it right and updated some of the event handlers.
Imports System.ComponentModel
Imports System.Net.MailPublic Class SendEngine
Private \_currentRetryCount As Integer Private \_maxRetryCount As Integer Private \_mailMessage As MailMessage Private \_isAlreadyRun As Boolean Public Event SendEmailCompleted As SendEmailCompletedEventHandler Public Sub SendEmailAsync(ByVal smtpClient As SmtpClient, ByVal message As MailMessage, ByVal retryCount As Integer) If \_isAlreadyRun Then Throw New InvalidOperationException("sendEngine doesn't support multiple concurrent invocations.") End If \_isAlreadyRun = True \_maxRetryCount = retryCount \_mailMessage = message AddHandler smtpClient.
-
I'm having problems with sending email using CBeyond from all of my programs in VB. So I decided to change my send function to SendAsync, and Async, and just send each message 1 at at a time and wait for the results so it can be logged when done. (Thus the SQLite Question earlier) So I thought this would be pretty easy, just change SmtpClient.Send(mailMessage) to smtpClient.SendAsync(mailMessage, cancelToken), but I guess now I need to add a callback. So I got some ideas from this link, and used some of the concepts. The part I don't understand is calling the function, and setting the Public Event for the callback. c# - Send email when using SmtpClient - Stack Overflow[^] I c#, the code is this, but I have no clue what it is, it's beyond my c# skills.
var sender = new EmailSender();
sender.SendEmailCompleted += (o, eventArgs)
=> Console.WriteLine(eventArgs.RetryCount);sender.SendEmailAsync(new MailMessage(), 5);
And I translated it using CodeTranslator CodeTranslator: Code Translation From VB.NET I'm looking at it and I have no clue what it is, I only recognize the first and last lines.
Dim sender As var = New EmailSender
sender.SendEmailCompleted = (sender.SendEmailCompleted + o)
,eventArgs
Unknown=GreaterConsole.WriteLine(eventArgs.RetryCount)
sender.SendEmailAsync(New MailMessage, 5)This is what I wrote from the C# example in the web page link. I'm pretty sure I got it right and updated some of the event handlers.
Imports System.ComponentModel
Imports System.Net.MailPublic Class SendEngine
Private \_currentRetryCount As Integer Private \_maxRetryCount As Integer Private \_mailMessage As MailMessage Private \_isAlreadyRun As Boolean Public Event SendEmailCompleted As SendEmailCompletedEventHandler Public Sub SendEmailAsync(ByVal smtpClient As SmtpClient, ByVal message As MailMessage, ByVal retryCount As Integer) If \_isAlreadyRun Then Throw New InvalidOperationException("sendEngine doesn't support multiple concurrent invocations.") End If \_isAlreadyRun = True \_maxRetryCount = retryCount \_mailMessage = message AddHandler smtpClient.
The code translator seems to have screwed up the event handler. The C# code:
sender.SendEmailCompleted += (o, eventArgs)
=> Console.WriteLine(eventArgs.RetryCount);would translate as something like this:
AddHandler sender.SendEmailCompleted, Sub(ByVal sender As Object, ByVal e As SendEmailCompletedEventArgs)
Console.WriteLine(eventArgs.RetryCount)
End SubIf you're using .NET 4.5 or later, I'd be inclined to use an Async[^] method, and use the SmtpClient.SendMailAsync method[^]:
Public Async Function SendEmailAsync(ByVal smtpClient As SmtpClient, ByVal message As MailMessage, ByVal retryCount As Integer) As Task(Of SendEmailCompletedEventArgs)
Dim currentTry As Integer = 0
While currentTry < retryCount
Try
Await smtpClient.SendMailAsync(message)
Return New SendEmailCompletedEventArgs(Nothing, False, Nothing, currentTry)Catch exception As Exception currentTry += 1 If currentTry >= retryCount Then Return New SendEmailCompletedEventArgs(ex, True, Nothing, currentTry) End If End Try End While ' Code should never reach here, but without this line you'll get a BC42105 warning: Return New SendEmailCompletedEventArgs(Nothing, True, Nothing, currentTry)
End Function
Your calling code can then use a
Using
block to clean up theSmtpClient
andMailMessage
instances:Public Async Function SendAllMessages() As Task
Using smtpClient As SmtpClient = CreateSmtpClient()
For Each item As SomeType In SomeListOfData
Using message As MailMessage = CreateMessageFor(item)
Dim result As SendEmailCompletedEventArgs = Await SendEmailAsync(smtpClient, message, RetryCount)
ProcessSendResult(item, result)
End Using
Next
End Using
End Function
"These
-
The code translator seems to have screwed up the event handler. The C# code:
sender.SendEmailCompleted += (o, eventArgs)
=> Console.WriteLine(eventArgs.RetryCount);would translate as something like this:
AddHandler sender.SendEmailCompleted, Sub(ByVal sender As Object, ByVal e As SendEmailCompletedEventArgs)
Console.WriteLine(eventArgs.RetryCount)
End SubIf you're using .NET 4.5 or later, I'd be inclined to use an Async[^] method, and use the SmtpClient.SendMailAsync method[^]:
Public Async Function SendEmailAsync(ByVal smtpClient As SmtpClient, ByVal message As MailMessage, ByVal retryCount As Integer) As Task(Of SendEmailCompletedEventArgs)
Dim currentTry As Integer = 0
While currentTry < retryCount
Try
Await smtpClient.SendMailAsync(message)
Return New SendEmailCompletedEventArgs(Nothing, False, Nothing, currentTry)Catch exception As Exception currentTry += 1 If currentTry >= retryCount Then Return New SendEmailCompletedEventArgs(ex, True, Nothing, currentTry) End If End Try End While ' Code should never reach here, but without this line you'll get a BC42105 warning: Return New SendEmailCompletedEventArgs(Nothing, True, Nothing, currentTry)
End Function
Your calling code can then use a
Using
block to clean up theSmtpClient
andMailMessage
instances:Public Async Function SendAllMessages() As Task
Using smtpClient As SmtpClient = CreateSmtpClient()
For Each item As SomeType In SomeListOfData
Using message As MailMessage = CreateMessageFor(item)
Dim result As SendEmailCompletedEventArgs = Await SendEmailAsync(smtpClient, message, RetryCount)
ProcessSendResult(item, result)
End Using
Next
End Using
End Function
"These
I knew it was a handler with the +=, but had no idea it was a sub call, Thanks! I was thinking last night how to handle the smtpclient with using so it can release it resources. I have a dialog that loops the collection of jobs in a listview, that generates a PDF attachment and then composes the message via await. In the composer function, it calls the SendMessage which is not await. I need to rethink that. It's OK to await again? I didn't want to pollute my composition function with the Send Function and separated them. Well, I'll add the handler and give it a spin, and then work on using the smtpclient. Thanks Richard! and Upvote
for each job in jobs
Await Compose
next
Function Compose()
Build Message
Attach PDF
Build smtpClient
Send
Log send errorEnd Function
Function Send
SendAsync
End Function
-
I knew it was a handler with the +=, but had no idea it was a sub call, Thanks! I was thinking last night how to handle the smtpclient with using so it can release it resources. I have a dialog that loops the collection of jobs in a listview, that generates a PDF attachment and then composes the message via await. In the composer function, it calls the SendMessage which is not await. I need to rethink that. It's OK to await again? I didn't want to pollute my composition function with the Send Function and separated them. Well, I'll add the handler and give it a spin, and then work on using the smtpclient. Thanks Richard! and Upvote
for each job in jobs
Await Compose
next
Function Compose()
Build Message
Attach PDF
Build smtpClient
Send
Log send errorEnd Function
Function Send
SendAsync
End Function
jkirkerx wrote:
It's OK to await again?
Yes, awaiting from within an async method that's been awaited is perfectly fine. :) You might want to add
.ConfigureAwait(False)
to the awaited expressions, where the remainder of the method doesn't need to execute in the same context:Await smtpClient.SendMailAsync(message).ConfigureAwait(False)
Async/Await - Best Practices in Asynchronous Programming[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
jkirkerx wrote:
It's OK to await again?
Yes, awaiting from within an async method that's been awaited is perfectly fine. :) You might want to add
.ConfigureAwait(False)
to the awaited expressions, where the remainder of the method doesn't need to execute in the same context:Await smtpClient.SendMailAsync(message).ConfigureAwait(False)
Async/Await - Best Practices in Asynchronous Programming[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
OK, I understand. Well, so far in code I got what I wanted out of it. I just need to log the error in the database so I can conclude that the email was sent to the Cbeyond mail servers, and it's out of my hands.
'This is the new sendEngine
Dim sE As New SendEngine()
sE.SendEmailAsync(smtpClient, mailMessage, 5)
AddHandler sE.SendEmailCompleted, _
Sub(sender As Object, e As SendEmailCompletedEventArgs)Console.WriteLine(e.Error)
If (e.Error IsNot Nothing) Thenmodel.Error\_Text = e.Error.HResult model.Error\_Text = e.Error.Message.ToString model.TimeStamp\_Error = DateTime.Now() ef\_model\_smtp\_resend.Write\_Smtp\_Send\_Record(model)
End If
End SubThanks for the help Richard! It would of taken me days to figure out the handler.