2

Where is my fault?

I have a class type Exception

public class ApiException : Exception {
  public ApiException(string message) : base(message) {
  }
}

In some situations I call throw new ApiException("Message"); For example here:

public static async Task<string> ValidateToken(string token) {
  Dictionary<string, string> values = new Dictionary<string, string> {
    { "token", token}
  };

  FormUrlEncodedContent content = new FormUrlEncodedContent(values);
  HttpResponseMessage response = await client.PostAsync(Globals.sso, content);

  string responseString = await response.Content.ReadAsStringAsync();

  if (response.IsSuccessStatusCode) {
    TokenResp result = JsonConvert.DeserializeObject<TokenResp>(responseString);
    if (result.Token != token)
      throw new ApiException("Token is invalid");
  } else {
    NonFieldResponse resp = JsonConvert.DeserializeObject<NonFieldResponse>(responseString);
    string msg = null;

    foreach (string message in resp.non_field_errors) {
      if (msg != null) msg += ", ";
      msg += message;
    }

    throw new ApiException(msg);
  }

In somewhere I need to catch exceptions like here:

try {
  Type = ValidateToken(token).Result;
} catch (ApiException ae) {
  Console.WriteLine(ae.Message);
} catch (Exception e) {
  Console.WriteLine(e.Message);
}

But catch (ApiException ae) doesn't happens, always catched simple Exception (where e.GetType() is AggregateException and e.InnerException.GetType() is ApiException).

How to catch my exception?

mjwills
  • 23,389
  • 6
  • 40
  • 63
Igor Cova
  • 3,126
  • 4
  • 31
  • 57
  • 4
    Can you create a [mcve]? Is it possible you've declared `ApiException` in two different places, so the one you're throwing isn't the same type as the one you're catching? – James Thorpe Jun 25 '18 at 13:08
  • 2
    In your example, both `catch` clauses do the same thing. How are you verifying one is hit but not the other? Be aware that the debugger isn't always fully correct in indicating the current line being executed. – Jeroen Mostert Jun 25 '18 at 13:09
  • 2
    Is your `ApiException` becoming another exception's `InnerException` at some point? – ProgrammingLlama Jun 25 '18 at 13:11
  • 1
    Based on your comment below about it being an `AggregateException`, I'm going to wonder if you're working with Tasks incorrectly. Either way, `AggregateException` has an `InnerExceptions` list, which will be wrapping your exception. – ProgrammingLlama Jun 25 '18 at 13:18
  • 2
    As @James said, an [mcve] is definitely required to give you a solution, but the answer is that an `AggregateException` is not an `ApiException`, so it's not getting caught. – ProgrammingLlama Jun 25 '18 at 13:19
  • Possible duplicate of [What benefit does the new "Exception filter" feature provide?](https://stackoverflow.com/questions/27082069/what-benefit-does-the-new-exception-filter-feature-provide) – mjwills Jun 25 '18 at 13:21

2 Answers2

4

-- edit, after seeing code that is even more real:

  • When your caller is not async, be careful because this can cause deadlocks:
// Type = ValidateToken(token).Result;
   Type = ValidateToken(token).GetAwaiter().GetResult();
  • when you caller method is also async:
Type = await ValidateToken(token); 

Both of these will 'unwrap' the aggregate exception.
Your custom exception is of course one of the InnerExceptions of that AggregateException.

bommelding
  • 2,969
  • 9
  • 14
2

You ApiException will not get caught properly unless you await the ValidateToken() call. When you use:

Type = ValidateToken(token)Result;

instead of:

Type = await ValidateToken(token);

Your exceptions will be wrapped in an AggregateException.

Using await properly will allow the proper exception to get caught.

Use this:

try {
  Type = await ValidateToken(token);
} catch (ApiException ae) {
  Console.WriteLine(ae.Message);
}
Kyle B
  • 2,328
  • 1
  • 23
  • 39
  • e.GetType().FullName = "System.AggregateException" – Igor Cova Jun 25 '18 at 13:16
  • 1
    @IgorCova, is your method Async? Tasks are wrapped in AggregateExceptions. – Michael Freidgeim Jun 25 '18 at 13:20
  • @MichaelFreidgeim yes – Igor Cova Jun 25 '18 at 13:20
  • `AggregateException` has a `Handle` method for such things. Checking the `InnerException` explicitly, in the assumption there's only one, is a bit of a smell; in that case `await` probably should have been used (or, in the rare case where a synchronous execution is desired, `.GetAwaiter().GetResult()`, which will propagate the single exception). – Jeroen Mostert Jun 25 '18 at 13:30
  • @JeroenMostert, right-I realized that, I was already working on an edit for that. Feel free to edit further – Kyle B Jun 25 '18 at 13:32