Gopal
Gopal

Reputation: 1340

Exception handling in async methods C#

I know this question has been asked several times, but, I'm looking slightly at a different variant.

public async Task<string> SomeAsyncMethod(string url)
{
     // do some URL validation
     if (!valid)
     {
          throw new Exception("some error");
     }
     // do async stuff now
     return await GetFromUrl(url)
}

// now in caller
public async Task<string> SomeOtherAsyncMethod(string input)
{
     var task = SomeAsyncMethod(input); 
    // there is potential chance that a validation fails and  
    //exception is thrown even before entering async parts of the called function

     // do some independent stuff here
    try
    {
        await task;
    } 
    catch(Exception e)
    {
        // log error 
    }

    // is the following code correct way to handle exceptions?
    if (!task.IsFaulted)
    {
        return task.Result; 
    }

    // log error from task.Exception 
    return null;

}

In the above code it may so happen that validation fails and exception is thrown even before the control enters async part of the method. Do we need to wrap the first call also around a try..catch block? My experiment showed that this is not useful. Instead, the task status is set to Faulted. So, I believe it is correct to check Task status and return data accordingly. Can C# pros comment on this?

Upvotes: 5

Views: 6411

Answers (2)

Stephen Cleary
Stephen Cleary

Reputation: 457322

Do we need to wrap the first call also around a try..catch block?

You may want to do so, as a defensive coding measure. "Precondition" exceptions in async methods suffer from the same problems as they do with enumerator blocks. In the async case, the precondition exceptions are used to fault the task, not raised directly. This is how I do precondition exceptions.

However, there is an alternative. It is possible for an implementation to "eagerly" do the precondition checks and only use faulted tasks to represent asynchronous exceptions. I.e.:

public Task<string> SomeMethodAsync(string url)
{
   // do some URL validation
   if (!valid)
   {
     throw new Exception("some error");
   }
   // do async stuff now
   return SomeMethodImplAsync(url);
}

private async Task<string> SomeMethodImplAsync(string url)
{
  return await GetFromUrl(url)
}

I don't do this myself, but this kind of approach does have its supporters. Most notably, Jon Skeet.

With that in mind, unless the documentation explicitly specifies that precondition exceptions will be placed on the returned task, you probably should include the call to SomeMethdAsync within a try block.

Upvotes: 4

Servy
Servy

Reputation: 203809

As you have already stated, when you have an async method that throws an exception calling the method will never throw, instead the returned tasks will simply be faulted. This is true even if an exception is thrown before the first await. If that's your desired functionality, then you already have it, and there is no need to change anything.

Upvotes: 4

Related Questions