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")]