I'm implementing EmailServer
for ASP.NET Identity.
I don't like how async...await
is not compatible with using
, and so my email method is synchronous.
So how can I call it from the framework's SendAsync
method?
public class EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
Email email = new Email();
return Task.FromResult<void>(email.Send(message));
}
}
In the code above, Task.FromResult()
gives me an error saying void
can't be used as an argument type. But email.Send()
returns void!
How to get out of this quagmire?
If you don't have a result, then don't try to return a result. Just return a plain, completed Task
:
public class EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
new Email().Send(message);
return Task.CompletedTask;
}
}
If you are stuck in pre-4.6 land, then you can use Task.FromResult<bool>(true)
instead.
All that said, I'm confused by your comment about "async...await
is not compatible with using
". In my experience, that works fine. And it would be much better if your method were in fact asynchronous. I think you would be better served by focusing on how to do that, rather than what the best/correct syntax is for faking an async
method.
Addendum:
I am still not clear on your concern about the use of using
. However, based on your comment, it seems you would like to use SmtpClient.SendAsync()
but are uncertain as to how to apply that in the context of async
/await
.
Unfortunately, even before async
/await
, we had lots of asynchronous methods in .NET, and those methods used the same naming as the convention for new awaitable methods. (To be clear: it's the naming that's unfortunate, not that the async methods existed :) ). However, in all cases, it is possible to adapt the old API to the new.
In some cases, it's as simple as using the Task.FromAsync()
method. That works with anything that supports the old Begin...
/End...
model. But the SmtpClient.SendAsync()
model is an event-based callback approach, which requires a slightly different approach.
NOTE: I noticed after writing the example below that the SmtpClient
class has a Task
-based method for asynchronous operation, SendMailAsync()
. So in reality, there's no need to adapt the older SendAsync()
method. But it's a useful example to use, to show how one might do such adaptation when a Task
-based alternative hasn't been provided.
Briefly, you can use TaskCompletionSource
with the SendCompleted
event on the SmtpClient
object. Here's an outline of what that would look like:
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;
}
}
}
The above will start the asynchronous operation, and use the SendCompleted
event's handler (i.e. the "callback" to which the documentation refers) to set the result for the TaskCompletionSource<bool>
object (the result value is never really used, but there's no plain-vanilla Task
version of TaskCompletionSource
…you have to have some value).
It uses await
, rather than returning the taskSource.Task
object directly, because that way it can correctly handle disposing the SmtpClient
object when the email operation has in fact completed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With