Reputation: 112
I have written a simple class for me to send reports which works well, however I now need to incorporate a log to check whether the send was successful or not.
A quick brief on my app: It has a main form that you can manually run the reports via buttons and if the app is run from the command line then the form is hidden.
When the form is shown the SmtpClient.SendComplete
event fires, but when the form is hidden it does not and also doesn't send the email. I have tried every which way to get it to work.
public static async Task SendAsync(string sendTo, string subject, string body = "", string attachment = "")
{
#if (DEBUG)
// If in DEBUG mode then send reports to lee.
sendTo = "developer";
#endif
try
{
SmtpClient client = new SmtpClient("smtp.server", 587)
{ Credentials = new NetworkCredential("username", "password") };
MailMessage message = new MailMessage
{ From = new MailAddress("mailFrom") };
message.To.Add(sendTo);
message.Subject = subject;
message.Body = body;
if (!string.IsNullOrEmpty(attachment))
message.Attachments.Add(new Attachment(attachment));
client.SendCompleted += (s,e) =>
{
if (e.Error != null)
{
Logger.FileLog(message.Subject, e.Error.ToString());
}
else
{
Logger.FileLog(message.Subject, "Message Sent");
}
client.Dispose();
message.Dispose();
};
Logger.FileLog(_subject, "Running Async");
await client.SendMailAsync(message);
Logger.FileLog(_subject, "Finished");
}
catch (Exception e)
{
Logger.FileLog(subject, $"Error {e.HResult}, {e.Message}, {e.InnerException.ToString()}");
}
}
I have tried async Task
, async void
, SendAsync
, SendMailAsync
, loops to wait for a callback.
Some of the logging is there just so I can see how far it got when running from the command line and it only ever gets as far as "Running Async" which is before it tries to send the email.
The code for detecting whether to show or hide the form as requested, the original project was written in VB, the above code is in a class library which was working until I tried to run Async.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
If CommandLineArgs.Count > 0 Then
Visible = False
RunSilent = True
ParseCommandLine()
Close()
Else
'Update to add from db, XML or Excel
Dim t As Task = Task.Run(
Sub()
LoadReports()
End Sub)
t.Wait()
End If
End Sub
Any help or advice will be greatly appreciated.
Upvotes: 1
Views: 1873
Reputation: 246998
You close right after processing command line, so chances are that you are not awaiting the method and Close
is being invoked before the email can be sent.
assuming ParseCommandLine
and LoadReports
are async functions then you should await them in the event handler
Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
If CommandLineArgs.Count > 0 Then
Visible = False
RunSilent = True
Await ParseCommandLine() 'wait for task to complete then close
Close()
Else
'Update to add from db, XML or Excel
Await LoadReports()
End If
End Sub
Note the removal of .Wait()
blocking call that could cause deadlock when mixed with async calls.
Reference Async/Await - Best Practices in Asynchronous Programming
Upvotes: 1