从异步方法调用同步方法

时间:2017-04-26 02:40:36

标签: c# asp.net asp.net-mvc async-await

我正在为ASP.NET Identity实现$customer = Mage::getSingleton("customer/session", array('name' => 'frontend'))->getCustomer();

我不喜欢EmailServerasync...await不兼容的方式,因此我的电子邮件方法是同步的。

那么如何从框架的using方法中调用它呢?

SendAsync

在上面的代码中,public class EmailService : IIdentityMessageService { public Task SendAsync(IdentityMessage message) { Email email = new Email(); return Task.FromResult<void>(email.Send(message)); } } 给出了一个错误,指出Task.FromResult()不能用作参数类型。但void返回void!

如何走出这个泥潭?

1 个答案:

答案 0 :(得分:9)

如果您没有结果,请不要尝试返回结果。只需返回一个简单的,完整的Task

public class EmailService : IIdentityMessageService
{
    public Task SendAsync(IdentityMessage message)
    {
        new Email().Send(message);
        return Task.CompletedTask;
    }
}

如果你被困在4.6之前的土地上,那么你可以改用Task.FromResult<bool>(true)

所有这一切,我对您对async...awaitusing不兼容的评论感到困惑。根据我的经验,这很好。如果你的方法实际上是异步的,那会好得多。我认为通过专注于如何做到这一点会更好,而不是伪造async方法的最佳/正确语法。

<强>附录:

我仍然不清楚您对使用using的担忧。但是,根据您的评论,您似乎希望使用SmtpClient.SendAsync(),但不确定如何在async / await的上下文中应用该问题。

不幸的是,即使在async / await之前,我们在.NET中有很多异步方法,并且这些方法使用与新等待方法的约定相同的命名。 (要清楚:这是不幸的命名,而不是异步方法存在:))。但是,在所有情况下,都可以将旧API调整为新的。

在某些情况下,它就像使用Task.FromAsync()方法一样简单。这适用于支持旧Begin... / End...模型的任何内容。但SmtpClient.SendAsync()模型是一种基于事件的回调方法,需要稍微不同的方法。

注意:在编写下面的示例后,我注意到SmtpClient类具有基于Task的异步操作方法SendMailAsync()。所以实际上,没有必要调整旧的SendAsync()方法。但是这是一个有用的例子,用来说明在没有提供基于Task的替代方案时如何进行这种调整。

简而言之,您可以在TaskCompletionSource对象上使用SendCompleted SmtpClient事件。这是一个看起来像什么的概述:

public class EmailService : IIdentityMessageService
{
    public async Task SendAsync(IdentityMessage message)
    {
        // I'm not familiar with "IdentityMessage". Let's assume for the sake
        // of this example that you can somehow adapt it to the "MailMessage"
        // type required by the "SmtpClient" object. That's a whole other question.
        // Here, "IdentityToMailMessage" is some hypothetical method you write
        // to handle that. I have no idea what goes inside that. :)
        using (MailMessage mailMessage = IdentityToMailMessage(message))
        using (SmtpClient smtpClient = new SmtpClient())
        {
            TaskCompletionSource<bool> taskSource = new TaskCompletionSource<bool>();

            // Configure "smtpClient" as needed, such as provided host information.
            // Not shown here!

            smtpClient.SendCompleted += (sender, e) => taskSource.SetResult(true);
            smtpClient.SendAsync(mailMessage, null);

            await taskSource.Task;
        }
    }
}

以上将启动异步操作,并使用SendCompleted事件的处理程序(即文档引用的“回调”)来设置TaskCompletionSource<bool>对象的结果(结果值为从来没有真正使用过,但是没有普通的Task TaskCompletionSource版本的await ......你必须拥有一些值。)

它使用taskSource.Task,而不是直接返回SmtpClient对象,因为这样可以在电子邮件操作实际完成时正确处理A对象的处理。