Coder Perfect

In C#, how do I safely invoke an async method without using the await keyword?

Problem

I have an async method that doesn’t return anything:

public async Task MyAsyncMethod()
{
    // do some stuff async, don't return any data
}

This is a call from another function that returns some data:

public string GetStringData()
{
    MyAsyncMethod(); // this generates a warning and swallows exceptions
    return "hello world";
}

In Visual Studio, calling MyAsyncMethod() without waiting gives the warning “Because this call is not awaited, the current method continues to run before the call is completed.” The following is taken from the warning page:

I’m sure I don’t want to wait for the call to end; I don’t have the time or the need to. However, the call may result in exceptions.

This is a problem I’ve run into a few times, and I’m sure it’s a common one with a common answer.

How can I call an async method without having to wait for the result?

For those who think I’m just waiting for the outcome, this is code that responds to a web request on our web service (ASP.NET Web API). In a UI context, waiting keeps the UI thread free, but in a web request call, waiting for the Task to finish before responding to the request increases response times for no reason.

Asked by George Powell

Solution #1

You might do the following to get the exception “asynchronously”:

  MyAsyncMethod().
    ContinueWith(t => Console.WriteLine(t.Exception),
        TaskContinuationOptions.OnlyOnFaulted);

This allows you to handle an exception that occurs on a thread other than the “primary” thread. This means you don’t have to “wait” for the thread that calls MyAsyncMethod() to call MyAsyncMethod(), but you may still do something with an exception—but only if one arises.

You could theoretically do something similar with await:

try
{
    await MyAsyncMethod().ConfigureAwait(false);
}
catch (Exception ex)
{
    Trace.WriteLine(ex);
}

…which would be useful if you needed to use try/catch (or using) specifically, but I prefer ContinueWith because you have to understand what ConfigureAwait(false) means.

Answered by Peter Ritchie

Solution #2

Make GetStringData an async function that awaits the task returned from MyAsyncMethod first.

If you’re certain you won’t need to handle MyAsyncMethod’s exceptions or know when it finishes, go ahead and do this:

public string GetStringData()
{
  var _ = MyAsyncMethod();
  return "hello world";
}

This is not a “common problem,” by the way. It’s unusual to wish to run some code without regard for whether or not it completes properly.

Update:

You might find my blog post on the matter beneficial if you’re on ASP.NET and want to return early. However, ASP.NET was not built for this, and there’s no guarantee that your function will run after the response has been received. Although ASP.NET will make every effort to allow it to execute, it cannot guarantee it.

So, for something basic like tossing an event into a log, where it doesn’t matter if you lose a few here and there, this is a perfect option. It’s not a viable option for any mission-critical tasks. In some cases, a more complicated architecture is required, with a persistent means to save operations (e.g., Azure Queues, MSMQ) and a separate background process to process them (e.g., Azure Worker Role, Win32 Service).

Answered by Stephen Cleary

Solution #3

Peter Ritchie’s response was exactly what I needed, and Stephen Cleary’s essay on returning early in ASP.NET was extremely useful.

The following Console program demonstrates the use and behavior of Peter’s approach utilizing Task as a more general problem (not unique to an ASP.NET context). ContinueWith(…)

static void Main(string[] args)
{
  try
  {
    // output "hello world" as method returns early
    Console.WriteLine(GetStringData());
  }
  catch
  {
    // Exception is NOT caught here
  }
  Console.ReadLine();
}

public static string GetStringData()
{
  MyAsyncMethod().ContinueWith(OnMyAsyncMethodFailed, TaskContinuationOptions.OnlyOnFaulted);
  return "hello world";
}

public static async Task MyAsyncMethod()
{
  await Task.Run(() => { throw new Exception("thrown on background thread"); });
}

public static void OnMyAsyncMethodFailed(Task task)
{
  Exception ex = task.Exception;
  // Deal with exceptions here however you want
}

GetStringData() does not wait for MyAsyncMethod() to complete, and exceptions generated in MyAsyncMethod() are handled in OnMyAsyncMethodFailed(Task task), not in the try/catch around GetStringData() ()

Answered by George Powell

Solution #4

As a result, I’ve come up with the following solution:

public async Task MyAsyncMethod()
{
    // do some stuff async, don't return any data
}

public string GetStringData()
{
    // Run async, no warning, exception are catched
    RunAsync(MyAsyncMethod()); 
    return "hello world";
}

private void RunAsync(Task task)
{
    task.ContinueWith(t =>
    {
        ILog log = ServiceLocator.Current.GetInstance<ILog>();
        log.Error("Unexpected Error", t.Exception);

    }, TaskContinuationOptions.OnlyOnFaulted);
}

Answered by Filimindji

Solution #5

This is known as “fire and forget,” and there is a follow-up.

Install nuget package.

Use:

MyAsyncMethod().Forget();

EDIT: There’s another method I’ve been utilizing recently:

_ = MyAsyncMethod();

Answered by wast

Post is based on https://stackoverflow.com/questions/15522900/how-to-safely-call-an-async-method-in-c-sharp-without-await