I have created a separate class to handle mail sending. To make it hassle free from future changes I have used dependency injection to design it. Now, when I try to use SendMessageAsync()
method, I want to check SendMailCompleted event to see status of message sent failed/succeeded. I am confused how I'm supposed to implement the event in the class that is implementing it. Without mentioning this event in the interface I won't be able to catch it in the injection class. Can any one suggest how to solve this? My interface looks like as follows
public interface IMailing
{
string Host { get; set; }
int Port { get; set; }
Task SendMailAsync(string toAddress, string subject, string body);
event SendCompletedEventHandler OnEmailSendComplete;
}
The class that is implementing the interface is as follows -
public class Mailing : IMailing
{
private SmtpClient client = new SmtpClient();
MailMessage mm = null;
public string Host{ get; set; }
public int Port { get; set; }
// do i need this? without event being in the interface I would have had this //two following lines to manually raise the event
public event SendCompletedEventHandler OnEmailSendComplete;
public delegate void SendCompletedEventHandler(object source, AsyncCompletedEventArgs e);
// following lines were generated from the vs2017 IDE
// how do I use it when actual Send mail completed event fires?
event System.Net.Mail.SendCompletedEventHandler IMailing.OnEmailSendComplete
{
add
{
throw new NotImplementedException();
}
remove
{
throw new NotImplementedException();
}
}
public async Task SendMailAsync(string toAddress, string subject, string body)
{
mm = new MailMessage(User, toAddress, subject, body);
client.SendCompleted += Client_SendCompleted;
await client.SendMailAsync(mm).ConfigureAwait(false);
}
private void Client_SendCompleted(object sender, AsyncCompletedEventArgs e)
{
OnEmailSendComplete?.Invoke(sender, e);
}
}
Now, the injection class uses constructor injection, which looks like follows -
public class MailingInjection
{
IMailing mailing = null;
private MailingInjection()
{ }
public MailingInjection(IMailing imail)
{
mailing = imail;
}
public async Task SenMailAsync(string to, string subject, string body)
{
mailing.OnEmailSendComplete += EmailSendCompleted;
await mailing.SendMailAsync(to, subject,body).ConfigureAwait(false);
}
private void EmailSendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
mailing.OnEmailSendComplete -= EmailSendCompleted;
}
}
I tried to put as less code as possible to explain my confusion so this code will not work in real scenarios but has the structure I believe. Please let me know if I have over exaggerated it. I appreciate any help.
Your code is conflating two different asynchronous patterns: the older event-based asynchronous pattern and the new task-based asynchronous pattern . In particular, SmtpClient.SendCompleted
is only used with SmtpClient.SendAsync
. Your code isn't using SendAsync
, so it doesn't need SendCompleted
. It can just use SmtpClient.SendMailAsync
instead:
public interface IMailing
{
string Host { get; set; }
int Port { get; set; }
Task SendMailAsync(string toAddress, string subject, string body);
// No event necessary.
}
public class Mailing : IMailing
{
private SmtpClient client = new SmtpClient();
MailMessage mm = null;
public string Host{ get; set; }
public int Port { get; set; }
public async Task SendMailAsync(string toAddress, string subject, string body)
{
mm = new MailMessage(User, toAddress, subject, body);
await client.SendMailAsync(mm).ConfigureAwait(false);
}
}
Usage:
public class MailingInjection
{
...
public async Task SenMailAsync(string to, string subject, string body)
{
await mailing.SendMailAsync(to, subject,body).ConfigureAwait(false);
}
}
As a final reminder, if your abstraction has only one implementation, it's not an abstraction. ;)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.