{"record":{"id":"2d34f7054baef93c","repo":"dotnet/maui","slug":"this-is-an-async-test-exception-thrown-from-c-cod","errorCode":null,"errorMessage":"This is an async test exception thrown from C# code!","messagePattern":"This is an async test exception thrown from C# code!","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"info","filePath":"src/Controls/samples/Controls.Sample/Pages/Controls/HybridWebViewPage.xaml.cs","lineNumber":215,"sourceCode":"\t\t\t\t{\n\t\t\t\t\tMessage = \"Hello from C#! \" + s,\n\t\t\t\t\tValue = i,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Demo method that throws an exception to showcase error handling\n\t\t\tpublic void ThrowException()\n\t\t\t{\n\t\t\t\tDebug.WriteLine(\"ThrowException called - about to throw\");\n\t\t\t\tthrow new InvalidOperationException(\"This is a test exception thrown from C# code!\");\n\t\t\t}\n\n\t\t\t// Demo async method that throws an exception\n\t\t\tpublic async Task<string> ThrowExceptionAsync()\n\t\t\t{\n\t\t\t\tDebug.WriteLine(\"ThrowExceptionAsync called - about to throw\");\n\t\t\t\tawait Task.Delay(100);\n\t\t\t\tthrow new ArgumentException(\"This is an async test exception thrown from C# code!\");\n\t\t\t}\n\t\t}\n\n\t\tpublic class SyncReturn\n\t\t{\n\t\t\tpublic string? Message { get; set; }\n\t\t\tpublic int Value { get; set; }\n\t\t}\n\t}\n}\n","sourceCodeStart":197,"sourceCodeEnd":226,"githubUrl":"https://github.com/dotnet/maui/blob/f377ff1c5ee04d334d8a925f50c83a6b7afddf03/src/Controls/samples/Controls.Sample/Pages/Controls/HybridWebViewPage.xaml.cs#L197-L226","documentation":"This is a deliberate demo exception thrown by the HybridWebView sample app. The ThrowExceptionAsync() method (an inner-class RPC target invokable from JavaScript) awaits a short delay and then throws ArgumentException to demonstrate how async exceptions cross the JS/C# boundary. It is not a library fault; it is sample code exercising HybridWebView's error-propagation contract.","triggerScenarios":"Invoking ThrowExceptionAsync from JavaScript via window.HybridWebView.InvokeDotNet('ThrowExceptionAsync') (e.g. the sample's 'Test C# Async Exception Handling' button), or calling it directly from C#.","commonSituations":"Running the Controls.Sample HybridWebView page and clicking the async-exception test button; copy-pasting the sample's RPC proxy class into a real app and forgetting to remove the throw; automated UI tests that walk every sample button.","solutions":["If you copied the sample proxy class, replace throw new ArgumentException(...) with your real async logic.","If intentionally testing, keep the call inside the JS try/catch the sample already provides around InvokeDotNet.","Confirm you are not invoking the demo ThrowExceptionAsync method from production code paths."],"exampleFix":"// before\npublic async Task<string> ThrowExceptionAsync()\n{\n    await Task.Delay(100);\n    throw new ArgumentException(\"This is an async test exception thrown from C# code!\");\n}\n\n// after\npublic async Task<string> GetDataAsync()\n{\n    await Task.Delay(100);\n    return \"real payload\";\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// JS side (the sample already does this)\ntry {\n  const result = await window.HybridWebView.InvokeDotNet('ThrowExceptionAsync');\n} catch (ex) {\n  console.error(ex.message, ex.dotNetErrorType);\n}\n\n// C# side, if calling directly\ntry { await proxy.ThrowExceptionAsync(); }\ncatch (ArgumentException) { /* expected in tests */ }","preventionTips":["Do not invoke demo Throw* methods from production code paths.","When reusing sample RPC proxy classes, delete or replace the intentional throw methods.","Keep a clear naming convention so test/demo methods are not called accidentally."],"tags":["hybridwebview","sample","async","exception-handling","csharp"],"backgroundTag":null,"analyzedSha":"f377ff1c5ee04d334d8a925f50c83a6b7afddf03","analyzedAt":"2026-08-13T14:26:18.069Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}