0

I am having a lot of troubles to catch an exception in a async DelegateCommand (Prism 5).

In constructor of the ViewModel:

cmdModificarPedido = New DelegateCommand(Of Object)(AddressOf OnModificarPedido, AddressOf CanModificarPedido)

In the ViewModel:

Private _cmdModificarPedido As DelegateCommand(Of Object)
Public Property cmdModificarPedido As DelegateCommand(Of Object)
    Get
        Return _cmdModificarPedido
    End Get
    Private Set(value As DelegateCommand(Of Object))
        SetProperty(_cmdModificarPedido, value)
    End Set
End Property
Private Function CanModificarPedido(arg As Object) As Boolean
    Return True
End Function
Private Async Sub OnModificarPedido(arg As Object)
    Try
        Await Task.Run(Sub()
                           Throw New Exception("My Exception")
                       End Sub)
        NotificationRequest.Raise(New Notification() With {
                       .Title = "OK",
                       .Content = "Command OK"
                   })

    Catch ex As Exception
        NotificationRequest.Raise(New Notification() With {
                    .Title = "Error",
                    .Content = ex.Message
                })

    End Try
End Sub

Why the Exception is not being catched? I know it is another thread, but it is supposed to be catched anyway by the external Try...Catch block (Try Catch outside of: await Task.Run(()).

enter image description here

Note: it is vb.net code, but a C# solution will be fine too.

UPDATE 2 Once I know there was a problem with my debugger configuration (first chance exceptions), I write a more realistic example with same problem:

Private Async Sub OnModificarPedido(arg As Object)
    Try
        Await Task.Run(Sub()
                           Try
                               throwMyException()
                           Catch ex As Exception
                               Throw New Exception(ex.Message)
                           End Try
                       End Sub)
        NotificationRequest.Raise(New Notification() With {
                       .Title = "Pedido Modificado",
                       .Content = "Pedido " + pedido.numero.ToString + " modificado correctamente"
                   })

    Catch ex As Exception
        NotificationRequest.Raise(New Notification() With {
                    .Title = "Error",
                    .Content = ex.Message
                })

    End Try
End Sub
Public Async Sub throwMyException()
    Throw New Exception("My Exception")
End Sub

And now it does not catch the exception when I press F5. It breaks in "throwMyException()", it does not catch the exception although it is called inside a Try Catch block.

Important: If I remove the Async word in "throwMyException", it does catch it!!!

What am I doing wrong now?

Thank you

Community
  • 1
  • 1
Carlos
  • 1,638
  • 5
  • 21
  • 39
  • Are you absolutely sure that *this code* will not catch the exception? – Stephen Cleary Dec 28 '16 at 15:54
  • I am absolute sure very few things in my life :) but I have pasted and copied the code, checked it, and it does not catch the exception. I am goind to update the question with a picture – Carlos Dec 28 '16 at 16:04
  • 1
    Looks like you've got first-chance exceptions turned on in the debugger. If you F5 from there, would it be caught? – Stephen Cleary Dec 28 '16 at 21:16
  • Yes, it does!!! Would it work fine in the executable file, then? – Carlos Dec 29 '16 at 09:40
  • I haven't got System.Exception checked in my debugger Exception Settings Window. Why does it stop? – Carlos Dec 29 '16 at 09:43
  • I have updated with a better example of what I was looking for, where I think the Exception Settings does not affect. Thank you – Carlos Dec 29 '16 at 10:36

1 Answers1

1

There was no problem with the original code you posted - the debugger was just catching the exception before your code did, which is perfectly normal.

With the updated code, the problem is the use of Async Sub. Exceptions cannot be directly caught from Async Sub methods. You should use (non-Async) Sub or Async Func(of Task) instead. This principle is known as "avoid async void" in my MSDN article on async best practices.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • I am doing something wrong, because I don't get it. If I change the signture to "Private Async Function OnModificarPedido(arg As Object) As Task", what about this code in the constructor "cmdModificarPedido = New DelegateCommand(Of Object)(AddressOf OnModificarPedido, AddressOf CanModificarPedido)"??? It shows this message: "The Task returned from this Async Function will be dropped, and any exceptions in it ignored. Consider changing it to an Async Sub so its exceptions are propagated", and the exception is not catched too. Thank you very much – Carlos Dec 29 '16 at 17:15
  • 1
    Wrong method. You should be changing `throwMyException`, not `OnModificarPedido`. – Stephen Cleary Dec 29 '16 at 17:36
  • You are a genius!!! That was exactly the problem!!! No async Sub solved my problem (I was not able to make it work with Async Func(of Task)). Thank you – Carlos Dec 30 '16 at 07:56