Skip to content

XAML Compiler generates incorrect lowercase resource URI when using custom Application-derived class in App.xaml #11260

@iyulab-caveman

Description

@iyulab-caveman

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:
// CustomStartup.cs
using System.Windows;

namespace ReproApp
{
    public class CustomStartup : Application
    {
    }
}
  1. Create App.xaml using the custom class as root element:
<!-- App.xaml -->
<local:CustomStartup
  x:Class="ReproApp.App"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:ReproApp">
  <Application.Resources>
  </Application.Resources>
</local:CustomStartup>
  1. Create code-behind:
// App.xaml.cs
namespace ReproApp
{
    public partial class App : CustomStartup
    {
    }
}
  1. Build the project - Builds successfully without errors
  2. 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:

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 <Application> 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:

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 <Application>
  • 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 <Application> 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions