c# - Catch Exception thrown by ASYNC DelegateCommand.Execute() when used as ICommand -


i'm using delegatecommands (prism) inside viewmodels expose outside icommands.

the caviat is: delegatecommand.execute implemented task execute(...) whereas icommand.execute implemented simple void execute(...).

i noticed this, because exceptions swallowed in execute handler. while typical behaviour asyncs not awaited did not expect occur icommand.execute (which has no sign of being async).

if execute icommand not able catch thrown exceptions delegatecommand since delegatecommands execute() method async whereas icommands not.

is there way catch thrown exception when using delegatecommand icommand?

[test] public void delegatetoicommandexecute() {     var dcommand = new delegatecommand(() => { throw new exception(); });     icommand command = dcommand;     command.execute(null); // doesn't fail due exception } 

making nunit test case async works, visual studio complains have async method without await await icommand.execute not possible.

casting explicitly delegatecommand possible fix unit test , not application's behaviour when exception thrown.

how should application working icommand deal async underlying calls swallowing exception?

delegatebase (from delegatecommand inherits) defines execute async void execute , awaits own task execute() call). while calling icommand.execute end calling async void under hood.

exceptions swallowed in execute handler.

they should not have been. according the source code, icommand.execute (correctly) implemented async void method awaits asynchronous command.

this means icommand.execute call not swallowing exception. however, cannot caught directly, because is asynchronous method. describe happens in detail in async best practices article: in case, exception re-raised within context of original call icommand.execute.

when icommand.execute called ui thread (i.e., mvvm binding), exception raised on ui thread, , whatever default behavior ui framework takes there (usually there's last-chance handler followed dialog/modal). when it's called unit test, uses whatever context provided unit test framework. describe async unit testing further in msdn article, gist of this: if make unit test async void, (the current version of) nunit give context. don't rely on behavior; has been recognized poor design decision , removed next version of nunit v3. if unit test framework not provide context (which should case, , will case in future), exception re-raised on thread pool context, cause arbitrary thread within test runner fail. how test runner responds indeterminate: in fact, if have 1 test, possible test runner finish before exception seen, indeed appear "lost". possible test runner ignore exceptions can't match specific test.

instead, solution two-fold:

  1. expose viewmodel properties type delegatecommand instead of icommand. unfortunate, , wish prism had iasynccommand expose instead, is. (fwiw, use own asynccommand implement iasynccommand).
  2. make unit tests async task (not async void), , await command's execution naturally.
  3. if of code calling execute directly (instead of using command bindings), should updated async task (or async task<t>) , await task returned execute.

note exception in icommand.execute not ignored @ runtime, have same effect exception raised event handler: must handled globally if handled @ all. not want. particularly problem asynchronous commands, since involve i/o operations prone errors that want handle gracefully.

to solve "meta-problem", you'll need revisit how want asynchronous commands behave. not uncommon put try/catch @ top of delegate, , update data-bound properties if fail. explore variety of similar solutions in msdn article on async mvvm commands, case "one size fits all" not apply.


Comments

Popular posts from this blog

javascript - Any ideas when Firefox is likely to implement lengthAdjust and textLength? -

matlab - "Contour not rendered for non-finite ZData" -

delphi - Indy UDP Read Contents of Adata -