5

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?

asked Nov 12, 2014 at 18:44
3
  • Does SomeAsyncMethod() really need to be async? Can't you just return GetFromUrl(url);? Commented Nov 12, 2014 at 18:55
  • @piedar.. yes it has to be async. It is a IO operation and hence no point in block-wait. Commented Nov 12, 2014 at 18:59
  • @Gopal: simply returning the value from GetFromUrl(url) would not block. It just would return the Task<string> that method returned instead of wrapping the task in yet another task. The difference would be that instead of the exception getting caught by the task wrapper, the caller SomeOtherAsyncMethod would see it. Which is better depends on your preference: wrapping SomeAsyncMethod's implementation in a task simplifies exception-handling in the caller, but at the (slight) expense of extra overhead (the task, the method's state machine, etc.). Either seems fine to me. Commented Nov 12, 2014 at 19:11

2 Answers 2

4

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.

answered Nov 12, 2014 at 19:11
Sign up to request clarification or add additional context in comments.

Comments

4

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.

answered Nov 12, 2014 at 19:18

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.