Reputation: 385
Suppose my service is runing and i have used a code for sending email notification in that service. The "EmailNotification" method is async and await.
Code of EmailNotification:
public async task EmailNotification()
{
try
{
//code here
using (SmtpClient smtp = new SmtpClient())
{
//mail sending
await smtp.Send(mailMessage);
}
}
Catch(Exception ex)
{
}
}
Used EmailNotification methos in my some test method like that:
public void test()
{
EmailNotification();
}
My Problem:
1)How can i log execptions of async and await method if my destination method test is not of type async?
2)Is it possible to use async method in non async type like above ia m using in test method?
Upvotes: 1
Views: 2029
Reputation: 456717
How can i log execptions of async and await method if my destination method test is not of type async?
The task returned from the async
method will contain any exceptions from that method. However, calling it in a "fire and forget" manner such as this means that the returned task is ignored. So, you'll have to have a try
/catch
in your async
method (which is already there) and log in the catch
.
Is it possible to use async method in non async type like above ia m using in test method?
Possible? Sure, it'll compile and run.
A good idea? Probably not.
On ASP.NET, any work done outside of an HTTP request is not guaranteed to complete. When your code calls EmailNotification
, it is starting some work and then completing the HTTP request (by sending a response). That send-email work is then done without an HTTP request, and may be lost if your app is recycled.
This is a fine approach if you're perfectly OK with emails disappearing occasionally without any logs or any other indicators that something went wrong. If you're not OK with that, then you'll need a more robust solution (such as a proper distributed architecture, as I describe on my blog). Or you can just outsource that part of it by using an email service such as SendGrid.
Upvotes: 2
Reputation: 10851
public static class TaskExtensions
{
/// <summary>
/// Waits for the task to complete, unwrapping any exceptions.
/// </summary>
/// <param name="task">The task. May not be <c>null</c>.</param>
public static void WaitAndUnwrapException(this Task task)
{
task.GetAwaiter().GetResult();
}
/// <summary>
/// Waits for the task to complete, unwrapping any exceptions.
/// </summary>
/// <param name="task">The task. May not be <c>null</c>.</param>
public static T WaitAndUnwrapException<T>(this Task<T> task)
{
return task.GetAwaiter().GetResult();
}
}
And then use it like this:
try
{
var t = EmailNotification();
t.WaitAndUnwrapException();
}
catch(Exception ex)
{
// log...
}
Alternatively:
public void test()
{
try
{
var t = EmailNotification();
t.GetAwaiter().GetResult();
}
catch(Exception ex)
{
// Do your logging here
}
}
You should always try to use await
/async
all the way, and avoid this pattern when possible. But when you need to call an async method from a non-async method you can use GetAwaiter().GetResult()
in order to await the task and also get the correct Exception (if any).
As mentioned in the comments there's already an excellent answer from Stephen Cleary in this question: How to call asynchronous method from synchronous method in C#? (which my code is based on)
Upvotes: 1