``Type.IsAssignableFrom`` returning false unexpectedly in plugin-loading scenario
This is a plugin framework. The "base" DLL with a plugin class that is subclassed by plugin DLLs is located in
{ROOT}/bin/fhcore.dll
, while plugins are located in {ROOT}/modules/{PLUGIN_NAME}/{PLUGIN_NAME.dll}
.
This plugin framework is loaded into the application process by .NET hosting, if that is somehow meaningful.
All plugins have project references with <Private>false</Private>
and <ExcludeAssets>runtime</ExcludeAssets>
, ex.
I first ensure bin/fhcore.dll
is loaded into AssemblyLoadContext.Default
.
Then for each plugin, I instantiate an AssemblyLoadContext
as such:
I then LoadFromAssemblyPath
the plugin into the context, and afterwards:
- I clearly see that only the plugin itself (and any non-plugin-core dependencies thereof) are in the FhLoadContext
- A duplicate reference to the core did not sneak in.
Yet, typeof(BaseModule).IsAssignableFrom(plugin_type)
still returns false
for a given public class PluginModule : BaseModule
in the plugin DLL. Why could that be?36 Replies
This exact scenario worked just fine when I just loaded every single plugin into
AssemblyLoadContext.Default
by force. This issue only arises when I give each a separate AssemblyLoadContext
. But documentation states that in such cases, the shared dependencies can be loaded into AssemblyLoadContext.Default
and things should still bind.is
plugin_type.BaseType == typeof(BaseModule)
:HmmNoted:
I tried the following:
and got:
what is
AssemblyLoadContext.GetLoadContext(type.Assembly)
for both of themone moment, please
oh, right, that'll explain it
if I loaded the shared dep into
AssemblyLoadContext.Default
, the instance of the shared dep I loaded into it is where I must get the type from
...am I guessing right?are you using the hosting API?
I am
the problem is that
fhcore
is not in AssemblyLoadContext.Default
well. i think that is the problem
i am not sure how it is finding it
I am under the impression I am loading it there?
I should probably store the
Assembly
the method in the constructor returnsi think what will be easier is to use
load_assembly
instead of load_assembly_and_get_function_pointer_fn
in your hostI see
What's the difference?
Or rather, how does that end up leading to this situation
the
load_assembly_and_get_function_pointer_fn
creates a new ALC for each component that you load. since, you are supposed to be able to load multiple of them
this is why you are seeing typeof(FhModule)
inside that IsolatedComponentLoadContext
thing. that is the one created by the host APIHm
To tell the truth, I more or less verbatim used the .NET sample for hosting, so I don't know how I'd go about changing that
There some example I can refer to?
there are the unit tests i guess https://github.com/dotnet/runtime/blob/f6b93319242155a72801a7bb4bc92faac2ada1a3/src/native/corehost/test/nativehost/host_context_test.cpp#L425
you acquire
load_assembly
and get_function_pointer
in the same way that you acquire load_assembly_and_get_function_pointer_fn
and then you just use them
there is documentation for what the methods all take here https://github.com/dotnet/runtime/blob/main/docs/design/features/native-hosting.md:catsweat:
I'll look into it
i still don't know how
fhcore
has sneaked into your custom ALCmakes two of us; although I will say this is a rather convoluted use case to put it most mildly...
I'm more or less "tacking on" .NET plugin loading into a process not my own in a way essentially identical to https://github.com/citronneur/detours.net
can you log every asssembly you load in the override of
Load
is one of them fhcore
absolutely, one moment please
it sure is
when it loads
fhcore
does you override return null or is assembly_path
non-null
(the rest of the output is as above)
just to make sure I'm not logging something entirely stupid:
I hope I did understand your instruction correctly
uh
type.BaseType.Assembly
oh, right, I'm a Grade-A idiot, one moment
...in my defense, it is 3:40AM
here we go.
ok, this is what i expect to see
sorry!
yes, this is back to where it was before.
fhcore
is loaded into both the component ALC and the default ALCright, and it is loaded into the component ALC due to the host
(because the host jumps to a static method in
fhcore
to bootstrap in the first place, I assume?)right, because that is the behavior of
load_assembly_and_get_function_pointer_fn
a-ha
so it is the same exact blunder as getting core snuck into the plugin's ALC, only marginally more subtle 😅
indeed
I had no clue
So, then, I have to try and figure it out from the unit tests
based on the sample i assume you copied it from, you probably have something like and you need to instead have something like
that does look awfully familiar, yes- here's the actual source https://github.com/peppy-enterprises/fahrenheit/blob/main/src/stage1/src/main.cpp
...best not look too close into it, though 😄
and once you have those function pointer, you should replace with something like
right
thank you so much for taking the time
done and dusted! :catlove:
learned quite a few new things today, thanks again!
:)