Calling a synchronous method from an asynchronous method

I am implementing EmailServer

for ASP.NET Identity.

I don't like how async...await

incompatible with using

, so my email method is synchronous.

So how can I call it from the framework method SendAsync

?

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

      

The above code Task.FromResult()

shows an error that void

cannot be used as an argument type. But it email.Send()

returns void!

How to get out of this quagmire?

+3


source to share


1 answer


If you have no result, don't try to return the result. Just return a simple, complete Task

:

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

      

If you are stuck on the ground before 4.6 then you can use Task.FromResult<bool>(true)

.

All that said, I am confused by your comment about " async...await

incompatible with using

". This works great in my experience. And it would be much better if your method was actually asynchronous. I think you'd be better off focusing on how to do it rather than what is the best / correct syntax to fake a method async

.

Adding:

I still don't understand your usage concern using

. However, based on your comment, it seems like you would like to use SmtpClient.SendAsync()

, but not sure how to apply this in the context of async

/ await

.

Unfortunately, even before async

/ await

we had a lot of async methods in .NET and these methods used the same as the convention for new expected methods. (To be clear: this was called unfortunate, not that asynchronous methods exist :)). However, in all cases, you can adapt the old API to the new one.



In some cases, this is as easy as using a method Task.FromAsync()

. This works with anything that supports the old Begin...

/ End...

. But the model SmtpClient.SendAsync()

is an event-based callback method that requires a slightly different approach.

NOTE. After writing the example below, I have noticed that the class SmtpClient

has a method of asynchronous operation Task

, SendMailAsync()

. Thus, there is really no need to adapt the old method SendAsync()

. But it is a useful example to use to show how such an adaptation can be made if an alternative c was Task

not provided.

In short, you can use TaskCompletionSource

with an event SendCompleted

on an object SmtpClient

. Here's a diagram of what it will look like:

public class EmailService : IIdentityMessageService
{
    public async Task SendAsync(IdentityMessage message)
    {
        // I'm not familiar with "IdentityMessage". Let assume for the sake
        // of this example that you can somehow adapt it to the "MailMessage"
        // type required by the "SmtpClient" object. That 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;
        }
    }
}

      

The above will start the asynchronous operation and use an event handler SendCompleted

(ie the "callback" which the documentation refers to) to set the result to the object TaskCompletionSource<bool>

(the result value is never used, but there is no Task

& hellip version . You should have what value).

It uses await

instead of returning an object taskSource.Task

directly, because that way it can handle the placement of the object correctly SmtpClient

when the email operation is actually completed.

+7


source







All Articles