Skip to content

WinUI 3 Cant instantiate a UserControl from a location outside the application package or directory (XamlParseException) #6299

Open

Description

Describe the bug

When instantiating a UserControl from outside the application package an XamlParseException is thrown from the UserControl constructor at this.InitializeComponent().

Exception thrown at 0x773B35D2 (KernelBase.dll) in HostApp.exe: WinRT originate error - 0x80004005 : 'Cannot locate resource from 'ms-appx:///Plugin/PluginUserControl.xaml'.'.
Exception thrown: 'Microsoft.UI.Xaml.Markup.XamlParseException' in WinRT.Runtime.dll
WinRT information: Cannot locate resource from 'ms-appx:///Plugin/PluginUserControl.xaml'.
XAML parsing failed.

Steps to reproduce the bug

See minimal reproducing repository https://github.com/williamfigtree/WinUIPluginIssue. Key steps to recreate:

  1. Create a class library "Plugin" using template "Class Library (WinUI 3 in Desktop)"

  2. Add a UserControl "PluginUserControl" using template "User Control (WinUI 3)" to Plugin.csproj

  3. Create an application "HostApp" using template "Black App, Packaged (WinUI 3 in Desktop)"

  4. Add the "PluginLoadContext" class from this tutorial https://docs.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support to HostApp.csproj

    using System;
    using System.Reflection;
    using System.Runtime.Loader;
    
    namespace HostApp
    {
        class PluginLoadContext : AssemblyLoadContext
        {
            private AssemblyDependencyResolver _resolver;
    
            public PluginLoadContext(string pluginPath)
            {
                _resolver = new AssemblyDependencyResolver(pluginPath);
            }
    
            protected override Assembly Load(AssemblyName assemblyName)
            {
                string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
                if (assemblyPath != null)
                {
                    return LoadFromAssemblyPath(assemblyPath);
                }
    
                return null;
            }
    
            protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
            {
                string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
                if (libraryPath != null)
                {
                    return LoadUnmanagedDllFromPath(libraryPath);
                }
    
                return IntPtr.Zero;
            }
        }
    }
  5. Add the following code to the App constructor. You may need to modify the path to Plugin.dll.

        public App()
        {
            this.InitializeComponent();
    
            // Attempt to load a UserControl from a plugin dll
            // PluginUserControl throws an XamlParsingExcpetion during instantiation
    
            // Locate plugin dll in the Plugin project bin directory
            var rootPath = Path.GetFullPath(@"..\..\..\..\..\..\..\..\", typeof(Program).Assembly.Location);
            var pluginDllPath = Path.Combine(rootPath, @"Plugin\bin\x86\Debug\net5.0-windows10.0.19041.0\Plugin.dll");
    
            // Instantiate PluginUserControl
            var pluginLoadContext = new PluginLoadContext(pluginDllPath);
            using (pluginLoadContext.EnterContextualReflection())
            {
                var pluginUserControl = Activator.CreateInstance("Plugin", "Plugin.PluginUserControl");
            }
        }
  6. Build Plugin.csproj

  7. Deploy and debug HostApp.csproj

Expected behavior

The UserControl is instantiated and the UserControl XAML resources supplied by the external project, package, or directory are located.

Screenshots

No response

NuGet package version

No response

Windows app type

  • UWP
  • Win32

Device form factor

Desktop

Windows version

November 2019 Update (18363)

Additional context

This is a blocking issue for applications which require plugins which supply their own UI.

Observed the issue with WinUI 3 1.0.0-preview3.

#3888 describes a similar requirement but does not come to an appropriate solution as it requires files from the plugin to be copied into the main package. This prevents separate build and distribution of applications and plugins.

#1365 (comment) and https://docs.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support suggest that AssemblyLoadContext is the intended mechanism for plugin support and do not indicate any separate system for XAML resources.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions