在 C# 中使函数非阻塞/异步的简单方法?

SB2*_*055 4 .net c# asynchronous task-parallel-library async-await

我有一个按钮——当用户点击它时——会发送一封电子邮件。我希望它立即返回并在后台发送电子邮件,而无需在处理电子邮件时阻止 UI。我四处寻找async/ await/etc 并找到了很多不同的方法 - 我正在寻找一个简单的解决方案。我的电子邮件代码:

public void SendEmail(string toAddress, string subject, string body, string code = null) {
    try {

        var fromAddressObj = new MailAddress("noreply@me.com", "Name");
        var toAddressObj = new MailAddress(toAddress, toAddress);
        const string fromPassword = "Password";

        var smtp = new SmtpClient {
            Host = "smtp.office365.com",
            Port = 587,
            EnableSsl = true,
            DeliveryMethod = SmtpDeliveryMethod.Network,
            UseDefaultCredentials = false,
            Credentials = new NetworkCredential(fromAddressObj.Address, fromPassword)
        };
        using (var message = new MailMessage(fromAddressObj, toAddressObj) {
            Subject = subject,
            IsBodyHtml = true

        }) {
            message.Body = body;
            smtp.Send(message);
        }

    } catch (Exception e) {
        Elmah.ErrorSignal.FromCurrentContext().Raise(e);
    }
}
Run Code Online (Sandbox Code Playgroud)

如何修改它以便呼叫者不被阻止?

i3a*_*non 6

SmtpClientSendMailAsync这样使用它,而不是Send在发送扫除了UI线程,但你仍然可以处理可能发生的任何异常:

private async void button_Click(object sender, EventArgs e)
{
   await SendEmailAsync(address, subject, body)
}

public async Task SendEmailAsync(string toAddress, string subject, string body, string code = null) 
{
    try 
    {
        var fromAddressObj = new MailAddress("noreply@me.com", "Name");
        var toAddressObj = new MailAddress(toAddress, toAddress);
        const string fromPassword = "Password";

        var smtp = new SmtpClient {
            Host = "smtp.office365.com",
            Port = 587,
            EnableSsl = true,
            DeliveryMethod = SmtpDeliveryMethod.Network,
            UseDefaultCredentials = false,
            Credentials = new NetworkCredential(fromAddressObj.Address, fromPassword)
        };
        using (var message = new MailMessage(fromAddressObj, toAddressObj)
        {
            Subject = subject,
            IsBodyHtml = true
        }) 
        {
            message.Body = body;
            await smtp.SendMailAsync(message);
        }
    }
    catch (Exception e) 
    {
        Elmah.ErrorSignal.FromCurrentContext().Raise(e);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果方法的同步部分async( 之前的部分await)仍然设法阻塞 UI 线程,您可以将其卸载到ThreadPool线程:

private async void button_Click(object sender, EventArgs e)
{
   await Task.Run(() => SendEmailAsync(address, subject, body))
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 不要在Task没有awaiting 的情况下启动它,除非您处于无法使用的情况await(UI 事件处理程序不是这些情况之一)
  • async void仅适用于 UI 事件处理程序。不要在其他任何地方使用它。


nvo*_*igt 5

您可以在任务中运行您的方法而不等待它:

private void button_Click(object sender, EventArgs e)
{
   Task.Run( () => SendEMail(address, subject, body) );
}
Run Code Online (Sandbox Code Playgroud)

  • 不需要“Task.Run”。`SmtpClient` 具有天然的异步 API。 (4认同)