NuGet Package DLL Loading Issue

NuGet Package DLL Loading Issue

jeremyperna7254
Contributor Contributor
851 Views
5 Replies
Message 1 of 6

NuGet Package DLL Loading Issue

jeremyperna7254
Contributor
Contributor

In a test project I am working on I am trying to use the FontAwesome.WPF NuGet package for icons to be displayed on a palette control. Here is the current solution structure

 

Solution

- Core.csproj (references UI.csproj for views)

- UI.csproj (the project that references the FontAwesome.WPF package)

 

In the WPF UserControl that needs the icons I have added the namespace declaration and usage of the icons like this

xmlns:fa="http://schemas.fontawesome.io/icons/"
...
<fa:ImageAwesome
    Icon="Plus"
    Width="16" Height="16"
    Margin="0 0 5 0"/>
<TextBlock Text="Connect To Existing Project" />

Everything in the XAML designer renders fine. However, when I NETLOAD my plugin from bin/Debug/Core.dll and then trigger the command that shows my palette with the icons I get the following error at the InitializeComponent method in the code-behind my user control

System.Windows.Markup.XamlParseException
  HResult=0x80131501
  Message=Could not load file or assembly 'FontAwesome.WPF, PublicKeyToken=0758b07a11a4f466' or one of its dependencies. The system cannot find the file specified.
  Source=PresentationFramework
  StackTrace:
   at System.Windows.Markup.XamlReader.RewrapException(Exception e, IXamlLineInfo lineInfo, Uri baseUri)
   at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
   at System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
   at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
   at UI.View.ProjectTabView.InitializeComponent() in C:\Users\jerem\source\repos\PluginUIDemo\UI\View\ProjectTabView.xaml:line 1

  This exception was originally thrown at this call stack:
    [External Code]

Inner Exception 1:
FileNotFoundException: Could not load file or assembly 'FontAwesome.WPF, PublicKeyToken=0758b07a11a4f466' or one of its dependencies. The system cannot find the file specified.

Now the part where I get really confused is that I have confirmed that the FontAwesome.WPF.dll is present in my output directory (bin/Debug/FontAwesome.WPF.dll). I also am referencing a MVVM NuGet package in UI.csproj in the same way and that works just fine (however the difference is this isn't being loaded during initialization of a user control).

  <ItemGroup>
    <PackageReference Include="CommunityToolkit.Mvvm">
      <Version>8.3.2</Version>
    </PackageReference>
    <PackageReference Include="FontAwesome.WPF">
      <Version>4.7.0.9</Version>
    </PackageReference>
  </ItemGroup>

Interestingly, I can fix this error by manually copying the FontAwesome.WPF.dll into the C:\Program Files\Autodesk\AutoCAD 2024 directory, which confirms that is where ACAD is looking for this package. What I don't understand is why ACAD is looking for this package in the program files directory (C:\Program Files\Autodesk\AutoCAD 2024) and not in the bin/Debug output directory where I indicated that my plugin dll is and all the other dlls that mine depends on are located. Is there something different about loading assemblies for user controls?

0 Likes
Accepted solutions (1)
852 Views
5 Replies
Replies (5)
Message 2 of 6

ActivistInvestor
Mentor
Mentor
Accepted solution

In many scenarios I've had to deal with, involving multiple managed extension apps that were all dependent on a common set of libraries, I use something like the following (which is vastly-simplified from the actual working code, which searches through the Applications subkey of the registry to find dependent assemblies).

 

This overly-simplified example should find and load a dependent .dll having the same location as the .dll containing the IExtensionApplication.

 

public class MyApplication : IExtensionApplication
{
   string myLocation;
   public void Initialize()
   {
      string path = typeof(MyApplication).Assembly.Location;
      myLocation = Path.GetDirectoryName(path);
      AssemblyLoadContext.Default.Resolving += OnResolve;
   }

   Assembly OnResolve(AssemblyLoadContext context, AssemblyName name)
   {
      string path = Path.Combine(myLocation, $"{name.Name}.dll");
      if(File.Exists(path))
      {
         return context.LoadFromAssemblyPath(path);
      }
      return null;
   }

   public void Terminate()
   {
   }
}

 

 

0 Likes
Message 3 of 6

jeremyperna7254
Contributor
Contributor

I took your idea of adding an event handler to the assembly resolution failure event and got it working with this code. Thank you so much for the response!

    public class Program : IExtensionApplication
    {
        private string _rootDirectory;

        public void Initialize()
        {
            string path = typeof(Program).Assembly.Location;
            _rootDirectory = Path.GetDirectoryName(path);
            AppDomain.CurrentDomain.AssemblyResolve += OnResolve;
        }

        private Assembly OnResolve(object sender, ResolveEventArgs args)
        {
            AssemblyName assemblyName = new AssemblyName(args.Name);
            string path = Path.Combine(_rootDirectory, $"{assemblyName.Name}.dll");
            if (File.Exists(path))
            {
                return Assembly.LoadFile(path);
            }
            return null;
        }

        public void Terminate() { }
    }
0 Likes
Message 4 of 6

kerry_w_brown
Advisor
Advisor

@ jeremyperna7254 and others

 

It's great that you were able to use the solution provided to solve your issue.

To my way of thinking you should be applying the solved credit to the poster of the solution, not to yourself.
What you have done is essentially stealing credit for someone elses knowledge and effort.

This is a peer to peer support group; unpaid and usually unthanked and uncredited.

 

If users continue to not thank or credit the people who take the time to decipher questions and attempt to resolve issues,  these users shouldn't be surprised if, before long, thay are ignored.

 

Regards

 


// Called Kerry or kdub in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect. ~ kdub
Sometimes the question is more important than the answer. ~ kdub

NZST UTC+12 : class keyThumper<T> : Lazy<T>;      another  Swamper
Message 5 of 6

ActivistInvestor
Mentor
Mentor

@jeremyperna7254 wrote:

I took your idea of adding an event handler to the assembly resolution failure event and got it working with this code. 

IOW, you took the code I posted and just renamed a few identifiers/variables?

 

Good Job!

0 Likes
Message 6 of 6

jeremyperna7254
Contributor
Contributor

Oh my goodness! I am so sorry! That was a complete misclick. Of course the credit should go to @ActivistInvestor. I just wanted to post the exact code that worked for me but I didn't intend to mark my reply as the accepated solution. I have marked @ActivistInvestor's reply as the accepted solution now. Thank you for pointing out the mistake and so sorry for the mess up. I really, really appreciate how engaged this forum is and all the helpful users. I definitely want to give credit for all the help you all provide.

0 Likes