简体   繁体   中英

How to implement an event if I have event in interface, also how I can use it in dependency Injection

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM