From 816ec0ba8f1cc0a7f78953edfbc8fb8344e07d16 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 08:58:57 -0500 Subject: [PATCH] Revert "[Android, iOS] Throw exceptions consistently for invalid StaticResource references to prevent relaunch crashes (#33859)" This reverts commit 6874c805d88ad295bd38b45f0743a9b57966f743. --- .../src/Xaml/ApplyPropertiesVisitor.cs | 9 ---- .../StaticResourceExtension.cs | 7 +-- .../DeviceTests/Xaml/StaticResourceTests.cs | 50 ------------------- .../HotReloadStaticResourceException.xaml.cs | 10 ++-- 4 files changed, 7 insertions(+), 69 deletions(-) delete mode 100644 src/Controls/tests/DeviceTests/Xaml/StaticResourceTests.cs diff --git a/src/Controls/src/Xaml/ApplyPropertiesVisitor.cs b/src/Controls/src/Xaml/ApplyPropertiesVisitor.cs index e3034080322e..e513cb13e37c 100644 --- a/src/Controls/src/Xaml/ApplyPropertiesVisitor.cs +++ b/src/Controls/src/Xaml/ApplyPropertiesVisitor.cs @@ -281,15 +281,6 @@ void ProvideValue(ref object value, ElementNode node, object source, XmlName pro } catch (Exception e) { - // StaticResourceExtension must always rethrow even when a handler is present — - // unlike other markup extensions, swallowing this exception would silently apply - // an invalid value to the property. Notify the handler first to log the error. - if (markupExtension is StaticResourceExtension) - { - Context.ExceptionHandler?.Invoke(e); - throw; - } - if (Context.ExceptionHandler != null) Context.ExceptionHandler(e); else diff --git a/src/Controls/src/Xaml/MarkupExtensions/StaticResourceExtension.cs b/src/Controls/src/Xaml/MarkupExtensions/StaticResourceExtension.cs index 26fe06836982..ef8757d883e2 100644 --- a/src/Controls/src/Xaml/MarkupExtensions/StaticResourceExtension.cs +++ b/src/Controls/src/Xaml/MarkupExtensions/StaticResourceExtension.cs @@ -30,15 +30,16 @@ public object ProvideValue(IServiceProvider serviceProvider) && !TryGetApplicationLevelResource(Key, out resource, out resourceDictionary)) { var xmlLineInfo = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) is IXmlLineInfoProvider xmlLineInfoProvider ? xmlLineInfoProvider.XmlLineInfo : null; - var ex = new XamlParseException($"StaticResource not found for key {Key}", xmlLineInfo); if (Controls.Internals.ResourceLoader.ExceptionHandler2 is var ehandler && ehandler != null) { + var ex = new XamlParseException($"StaticResource not found for key {Key}", xmlLineInfo); var rootObjectProvider = (IRootObjectProvider)serviceProvider.GetService(typeof(IRootObjectProvider)); var root = rootObjectProvider.RootObject; ehandler.Invoke((ex, XamlFilePathAttribute.GetFilePathForObject(root))); + return null; } - // Throw an exception when the key is not found - throw ex; + else + throw new XamlParseException($"StaticResource not found for key {Key}", xmlLineInfo); } Diagnostics.ResourceDictionaryDiagnostics.OnStaticResourceResolved(resourceDictionary, Key, valueProvider.TargetObject, valueProvider.TargetProperty); diff --git a/src/Controls/tests/DeviceTests/Xaml/StaticResourceTests.cs b/src/Controls/tests/DeviceTests/Xaml/StaticResourceTests.cs deleted file mode 100644 index f8ae44a982b6..000000000000 --- a/src/Controls/tests/DeviceTests/Xaml/StaticResourceTests.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using Microsoft.Maui.Controls; -using Microsoft.Maui.Controls.Xaml; -using Xunit; - -namespace Microsoft.Maui.DeviceTests; - -[Category(TestCategory.Xaml)] -public class StaticResourceTests : IDisposable -{ - [Fact("Issue #23903: Missing ControlTemplate with exception handler should throw")] - [RequiresUnreferencedCode("XAML parsing may require unreferenced code")] - public void MissingControlTemplate_WithExceptionHandler_ShouldThrow() - { - // Issue #23903: StaticResourceExtension should always throw when resource is not found, - // even when an exception handler is present (for debug/hot reload scenarios). - // This prevents the app from crashing when relaunching. - - Controls.Internals.ResourceLoader.ExceptionHandler2 = (ex) => { }; - - var xaml = """ - - - - """; - - var page = new ContentPage(); - - // Should throw an exception even with handler present - bool exceptionThrown = false; - try - { - page.LoadFromXaml(xaml); - } - catch (Exception) - { - exceptionThrown = true; - } - - Assert.True(exceptionThrown, "Expected an exception to be thrown for missing ControlTemplate"); - } - - public void Dispose() - { - Controls.Internals.ResourceLoader.ExceptionHandler2 = null; - } -} \ No newline at end of file diff --git a/src/Controls/tests/Xaml.UnitTests/HotReloadStaticResourceException.xaml.cs b/src/Controls/tests/Xaml.UnitTests/HotReloadStaticResourceException.xaml.cs index 525413e5079f..0aaf9243289e 100644 --- a/src/Controls/tests/Xaml.UnitTests/HotReloadStaticResourceException.xaml.cs +++ b/src/Controls/tests/Xaml.UnitTests/HotReloadStaticResourceException.xaml.cs @@ -47,14 +47,10 @@ internal void MissingResourceExceptionAreHandled(XamlInflator inflator) handled = true; Assert.Equal(13, xpe.XmlInfo.LinePosition); } + }; - - // Now expect the exception to be thrown (after handler is invoked) - var exception = Assert.Throws(() => new HotReloadStaticResourceException(inflator)); - - // Verify handler was invoked and exception details are correct - Assert.True(handled, "Exception handler was not invoked"); - Assert.Contains("StaticResource not found for key MissingResource", exception.Message, System.StringComparison.Ordinal); + var page = new HotReloadStaticResourceException(inflator); + Assert.True(handled, "Exception was not handled"); } #else [Fact(Skip = "This test runs only in debug")]