DotNetCorePlugins: Could not load System.Data.SqlClient?
Describe the bug I’m creating an application which will load plugins from a directory (.\Extensions) in .NET Core 3.1 that’s why I chose this library. Previously (in .NET 4.6.2) I was using AppDomain.AssemblyResolve to resolve dependencies and share some assemblies with the plugins. More details below.
My project structure is basically this :
- A main host app,
- a core logic library (shared with plugins),
- a UI library (optionally shared with plugins)
The plugins will reference the core library and the UI library (in some cases). The main host app will resolve dependencies of the plugins using AppDomain.AssemblyResolve and share the core logic and UI libs with them.
This method still works. But I want features of this library such Unloading, HotReload, etc. So I switched to use this library and changed the code correspondingly.
But the problem is all 3 libraries are WPF .NET Core 3.1 libraries
The Core logic library depends on System.Drawing and the UI library depends on a 3rd party library (ModernWpf)
So to overcome the isolation boundry I have to share the types common to them like this :
private static PluginLoader GetDefaultLoader(string dllloc)
{
return PluginLoader.CreateFromAssemblyFile(
dllloc,
isUnloadable: true,
sharedTypes: new Type[]
{
typeof(Core.ExtensionBase),
typeof(UI.BuskBar.IBuskBarItem),
typeof(ModernWpf.ApplicationTheme),
typeof(ModernWpf.Controls.AppBarButton),
typeof(System.Drawing.Image),
});
}
I expected it to work like in .NET 4.6.2 (using AppDomain.AssemblyResolve) but it doesn’t. It throws this System.IO.FileNotFoundException saying
"Could not load file or assembly 'System.Data.SqlClient, Version=4.6.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified."
None of my projects/their dependencies depend on System.Data.SqlClient. I checked all of their *.deps.json. What should I do?
To Reproduce Steps to reproduce the behavior: I’m on a tight schedule and I can’t provide any repro of it but basically
- Create 2 WPF class library projects (one *.Core -> depends on System.Drawing.Common and one *.UI -> depends on ModernWpf).
- Reference those 2 in a new WPF Application project.
- Create a skeletal structure of my project -> a abstract class ExtensionBase in the *.Core project and a interface IBuskBarItem in *.UI project.
- Create a basic WPF class library project called MyPlugin reference the UI and Core project with copy local set to false.
- Try to load the plugin assembly (MyPlugin.dll) using the afore-mentioned GetDefaultLoader(path_to_plugin).
- You will get a System.IO.FileNotFoundException like I mentioned above.
Expected behavior I don’t have any dependencies to System.Data.SqlClient. I want mine to work like it did in .NET 4.6.2
Screenshots
Additional context I even tried to remove the *.Core and *.UI references from the plugin and modified the loading as
private static PluginLoader GetDefaultLoader(string dllloc)
{
return PluginLoader.CreateFromAssemblyFile(
dllloc,
isUnloadable: true,
sharedTypes: new Type[]
{
typeof(Core.ExtensionBase)
});
}
The plugin is basically just an empty dll but it still throws the same error.
It only works if there are no shared types (But what’s the point of plugin then?) like this:
private static PluginLoader GetDefaultLoader(string dllloc)
{
return PluginLoader.CreateFromAssemblyFile(
dllloc,
isUnloadable: true,
sharedTypes: new Type[] { });
}
The architecture of my project :
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 62 (2 by maintainers)
I am building with .net 6, creating a simple demonstration of my own with WPF user control plugins. After getting the Could not load System.Data.SqlClient issue, and finding this thread, I found adding Microsoft.Windows.Compatibility 6.0.0 fixed it, for now. I did not need anything project settings or config files, or OleDb reference. I’m still not really understanding the issue, for now.
To help those coming back here I had to do the following to get it to work:
Situation: I have a dotnetcore 3.1 lib that is of the type:
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop" ...
with<UseWPF>true</UseWPF>
I use this project to contain common things that the plugins rely on. The plugins can have UI configuration, which they themselves provide, but having a common set of controls they can use is helpful.In this core project i had to add the following additional properties
I then had to add a package reference to
<PackageReference Include="Microsoft.Windows.Compatibility" Version="3.1.1" />
This still resulted in some issues - namely that a specifc version of System.Data.Odbc could not be loaded. Noticed that there were no binding redirects generated in my config file for this dll, so adding an app.config to the project with the following got me further:
This made progress, but still resulted in complaints about the right version of
System.Data.OleDb
not loaded. Noticed this binding redirect was also missing, but no matter what i tried to do to manually add it, no luck, so instead I added it as a package reference:<PackageReference Include="System.Data.OleDb" Version="4.7.1" />
And voila, it worked.
@natemcmaster - IMHO, this dance sucks, I dont even use any
System.Data.*
libs. I wish there was an easier way to get this to work without what seems like black dll-magic hackery. But at least there’s a workaroundI think, I have found a solution that could explain the behavior and that works for me … it is named Microsoft.Windows.Compatibility
Now working in a new approach to find the real problem of assembly loading. Talk to you in a while.
5.0.100-preview.5.20279.10
Actually this problem appeared in the initial tests that I made of this library and then I managed to solve it, with which I took advantage of its use, but I am trying to remember what the solution path was. Since we came from using MEF for the implementation of plugins, what was missing in the McMaster library was detecting the available plugins without loading the assemblies, so implement the metadata reading of the files through attributes, with which a list of the available plugins and their characteristics is obtained to be able to select them from a categorized list, thus obtaining the path to the assembly that contains it and the name of the plugin. With this data the creation of the instance is done with the current library, which is where the infamous SqlClient error appears.