typeof(T).IsAssignableFrom does not work as I expected
There is a method in a generic class
PluginLoader<TPlugin> : IPluginLoader<TPlugin>
:
There is also an interface IWebPlugin
with implementation Plugin1
This method is called with an assembly, containing Plugin1
and tries to create an instance of it. It worked before I made PluginLoader generic, but now typeof(TPlugin).IsAssignableFrom(t)
returns false.
Plugin1.GetInterface("IWebPlugin")
returnsIWebPlugin
, typeof(TPlugin
gets IWebPlugin
too, but the original condition fails nevertheless.
Here's my result of playing with the debugger
Why if Plugin1 implements IWebPlugin and typeof(TPlugin) is IWebPlugin, Plugin1 is not assignable from IWebPlugin?6 Replies
is
typeof(TPlugin) == debugTypes[0].GetInterface("IWebPlugin")
true? is typeof(TPlugin) == typeof(IWebPlugin)
true?I have tried to debug it for a while and as far as I can tell, the problem is not really in this method. I have a prototype project that uses the same mechanism to resolve assemblies and create instances of IWebPlugin as in this case. It seems to me that I have messed up elsewhere but now it's too late and the debugger went nuts, so I'll try to solve it tomorrow and post an answer for history.
yes, my suspicion is that you have loaded these plugins incorrectly
in such a way that there are two different
IWebPlugin
interfaces
the things i suggested would have confirmed that if it was the caseI know this unrelated to your question, but important aspect to keep in mind when writing plugin systems via assembly loading is the potential memory leak when not unloading the assembly properly after the plugin is not needed anymore.
Also, sandboxing. But that's another issue.
I have an implementation that unloads assemblies but it does not prevent all memory leaks 'cause it's up to plugin's dev to ensure that when needed everything shuts down properly and there are no references to anything in the loaded context, so it can be collected by the GC when allowed
Also I have the solution to my problem 😎
The structure of my projects is the following:
- PluginBase - NuGet package w/ the loader and IWebPlugin interface
- Plugin1 - A test plugin
- MVC - Web project
MVC references PluginBase
Plugin1 references PluginBase
but even though they reference the same package with the same version, they reference their respective local copies, created on build action. It resulted in 2 absolutely identical IWebPlugin types loaded with the only difference being Module properties linking to different sources.
The solution I have found after some thinking with @Left2Dotnet
First, I have to exclude PluginBase from the build outptut, adding to the
<PackageReference...>
Then I want to allow my Plugin1 to get and load the .dll of the PluginBase from MVC's dll folder. I did this by using .runtimeconfig.json
I have created Plugin1.runtimeconfig.template.json
in the Plugin1's project root and added the following:
It will try to look for .dll
dependencies in the parent folder too (because plugins are located in /Plugins folder)
And the problem is officially solved
The original prototype worked because I used a direct ProjectReference in both MVC and Plugin projects thus the .dll
was the same and types did match fullythis article helped a lot
https://natemcmaster.com/blog/2017/12/21/netcore-primitives/
Deep-dive into .NET Core primitives: deps.json, runtimeconfig.json,...
Blog posts about software development, plus some other stuff.