I call a method that, with the exception, throws it up to process in external code

private async void FillCurrentWeather(string place) { XmlSerializer serializer = new XmlSerializer(typeof(Current)); string xml = await GetWeather(CurrentWeatherUrl,place,7); if (xml != null) { try { TextReader reader = new StringReader(xml); Current forecast = (Current)serializer.Deserialize(reader); PlaceName.Content = forecast.City.Name + "," + forecast.City.Country; CurrentWeather.Update(forecast); reader.Dispose(); } catch (InvalidOperationException ex) { throw new InvalidOperationException(ex.Message, ex.InnerException); } } } 

External code

 try { FillCurrentWeather(place); FillDayWeather(place); FillWeekWeather(place); } catch (InvalidOperationException ex) { MessageBox.Show("Ошибка при обработке данных внешнего сервиса\n" + ex.Message); } 

But the exception is not handled and pops up in the debugger. What could be the reason?

  • And what is the exception in the debtor? Copy it here, please. - Rostislav Dugin
  • The one I'm trying to intercept. InvalidOperationException An unhandled exception of type 'System.InvalidOperationException' occurred in mscorlib.dll Additional information: There is an error in the XML document (1, 1). - Vladimir
  • one
    Hm ... Can you show the complete code of the method that throws an exception? - Rostislav Dugin
  • four
    "pops up in the debugger" - when debugging in VS or something? Then see what Exception Settings are exposed. Debug -> Windows -> Exception Settings ( Ctrl+Alt+E ). - i-one
  • recommendation: throw; instead of throw new Inva...; - Igor

1 answer 1

At runtime, under the debugger, all the exceptions marked in the Debug -> Windows -> Exception Settings ( Ctrl + Alt + E ) drop out. This is normal. If you continue execution of the program ( F5 ), then your catch blocks will work further.

UPD

With the addition of the complete code, the real reason became clear, to which the previous paragraph has nothing to do. The problem is this:

 async void FillCurrentWeather 

For a complete understanding of how async / await works, refer to the video . Here I will briefly describe what happens during the execution of the program. So:

  1. In the try block of the external code, the FillCurrentWeather(place); method is FillCurrentWeather(place); .
  2. Running the FillCurrentWeather method reaches this line and leaves it *:

     string xml = await GetWeather(CurrentWeatherUrl,place,7); 
  3. In the try block of the external code, all other methods are processed.
  4. The GetWeather method completes execution, execution of the FillCurrentWeather method FillCurrentWeather , an exception is thrown. BUT! The try/catch in the external code is already complete, it cannot catch this exception! Therefore, an exception is thrown at the topmost level as an unhandled ( UnhandledTaskException ).

async void are dangerous for these very reasons:

  • we don't know when they actually end
  • accordingly, we cannot adequately respond to exceptions in such methods

async void signature can only be used for events and methods that have eventual semantics, plus not forgetting to completely wrap the whole body of such methods in try/catch , because if an exception occurs, you either get an unhandled exception (if it occurs in the UI stream), or if it originated in the thread of the pool, you either will not know about it, or this exception will kill the process (in the case of .NET 4.0 it will be like that).

What are your solutions? In this case, there is only one: change the method signature to async Task and wait for the end of this method in external code.

And another small FillCurrentWeather advice: in your case, the try/catch in the FillCurrentWeather method is not needed at all, so that it essentially does nothing. Just remove it. (And henceforth, if you want to throw exceptions, wrapping them in others, always include the exception as a whole, rather than its InnerException , which may not be: throw new Exception("This is new exception", e) ).


* in fact, this is a simplification, and execution will continue in depth until the moment when the call goes to the IO device. It is only important that the program does not wait for the completion of this method.

UPD2

In order not to lose the parallelization of obtaining weather data, which was unwittingly achieved when using async void methods, you need to use Task.WhenAll :

 try { var currentTask = FillCurrentWeather(place); var dayTask = FillDayWeather(place); var weekTask = FillWeekWeather(place); await Task.WhenAll(currentTask, dayTask, weekTask); } catch (InvalidOperationException ex) { MessageBox.Show("Ошибка при обработке данных внешнего сервиса\n" + ex.Message); } 
  • Thanks, did as you said. Now I’m waiting for each method to complete using await. Such a question, is the asynchrony now completely gone? In this case, it is not critical, but still this option does not please. - Vladimir
  • one
    @ Vladimir updated the answer. - andreycha