XAML Compiler generates incorrect lowercase resource URI when using custom Application-derived class in App.xaml
- Dominant language
- C#
- Stars
- 7.7k
- Forks
- 1.3k
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 61
Description
## Summary
When using a custom class that derives from `Application` as the root element in `App.xaml`, the XAML compiler generates a lowercase resource URI (`app.xaml`) instead of preserving the actual file name case (`App.xaml`). This causes a runtime error because the resource cannot be located.
## Environment
- .NET Version: 10.0
- WPF Version: 10.0
- OS: Windows 11
- SDK Style Project: Yes
## Steps to Reproduce
1. Create a custom class that inherits from `Application`:
```csharp
// CustomStartup.cs
using System.Windows;
namespace ReproApp
{
public class CustomStartup : Application
{
}
}
```
2. Create `App.xaml` using the custom class as root element:
```xaml
```
3. Create code-behind:
```csharp
// App.xaml.cs
namespace ReproApp
{
public partial class App : CustomStartup
{
}
}
```
4. Build the project - **Builds successfully without errors**
5. Run the application - **Runtime error occurs**
## Expected Behavior
The application should start successfully, with the XAML compiler generating the correct resource URI matching the actual file name: `/ReproApp;component/App.xaml`
## Actual Behavior
Runtime error occurs:
```
System.IO.IOException: Cannot locate resource 'app.xaml'.
at MS.Internal.AppModel.ResourcePart.GetStreamCore(FileMode mode, FileAccess access)
at System.IO.Packaging.PackagePart.GetStream(FileMode mode, FileAccess access)
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at ReproApp.App.InitializeComponent() in App.xaml:line 1
```
The generated code in `obj/.../App.g.cs` contains a **lowercase URI**:
```csharp
public void InitializeComponent() {
if (_contentLoaded) {
return;
}
_contentLoaded = true;
System.Uri resourceLocater = new System.Uri("/ReproApp;component/app.xaml", System.UriKind.Relative);
// ^^^^^^^^
// lowercase - should be App.xaml!
System.Windows.Application.LoadComponent(this, resourceLocater);
}
```
## Key Observations
1. **No `App.baml` file is generated** in the obj folder during build
- Other XAML files (like `MainWindow.xaml`) are correctly compiled to `.baml`
- This suggests the ApplicationDefinition is not being processed correctly
2. When using `` as the root element (standard approach), everything works correctly
3. The issue only occurs when using a custom `Application`-derived class as the root element
4. The XAML compiler appears to not recognize the custom Application class as a valid ApplicationDefinition
5. The lowercase URI in the generated code doesn't match the actual file name, which could cause issues on case-sensitive file systems
## Workaround
Remove `App.xaml` entirely and manually create the entry point:
```csharp
public partial class App : CustomStartup
{
[STAThread]
public static void Main()
{
var app = new App();
app.Run();
}
}
```
## Root Cause Analysis
The XAML compiler (`MarkupCompilePass1` task) seems to have issues when:
- The root element of `App.xaml` is not ``
- A custom class derived from `Application` is used instead
This results in:
1. The `App.baml` resource not being generated
2. An incorrect lowercase resource URI being generated
3. A mismatch between the expected and actual resource location at runtime
## Proposed Fix
The XAML compiler should either:
1. **Properly support custom Application-derived classes as root elements** in ApplicationDefinition files, OR
2. **Provide a clear compile-time error** indicating that only `` is supported as the root element in App.xaml
## Additional Context
This issue was discovered while working with a framework that uses a custom `Startup` class derived from `Application` to provide additional initialization logic. The workaround of removing `App.xaml` works but is not intuitive and requires manual Main() method creation.
Related WPF build targets: `Microsoft.WinFX.targets` (MarkupCompilePass1 task)
Contributor guide
Assessment
This issue has not been assessed yet.