从异步方法调用同步方法

Jon*_*ood 4 c# asp.net asp.net-mvc async-await

我正在实现EmailServerASP.NET身份.

我不喜欢怎么async...await不兼容using,所以我的电子邮件方法是同步的.

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

public class EmailService : IIdentityMessageService
{
    public Task SendAsync(IdentityMessage message)
    {
        Email email = new Email();
        return Task.FromResult<void>(email.Send(message));
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,Task.FromResult()给我一个错误,说void不能用作参数类型.但是email.Send()回归无效!

如何走出这个泥潭?

Pet*_*iho 9

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

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

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

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

附录:

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

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

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

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

简单地说,可以使用TaskCompletionSourceSendCompleted该事件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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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