http://www.gotdotnet.com/team/clr/LoadFromIsolation.aspx
My development team has stumbled into a problem that's described by this
article. Our app uses plug-in assemblies for specialized functionality;
each one is located in a separate subdirectory below the main app
directory. One of these has a static dependency to another plugin, so
that the resultant directory and file layout looks like...
AppBase ---- Plugin1Dir
---- Plugin1.dll
---- Plugin2Dir
---- Plugin2.dll
---- Plugin1.dll
Each plugin is signed with a strongname. The main app does not know in
advance which of these has been purchased or installed so it does not make
any assumptions about what is there and it does not consider load order
dependencies. The main app uses the AssemblyResolve event to find
referenced assemblies in the subdirectories. Plugin1 uses a web service,
so the first time it connects to the web service a proxy assembly is
emitted by the runtime and loaded into the app domain.
When the app does a LoadFrom on Plugin1Dir/Plugin1.dll the runtime loads
it into the appdomain as a path-based reference. When the LoadFrom is done
on Plugin2Dir/Plugin2.dll it loads Plugin1.dll again into the app domain,
this time as a static reference, so that Plugin1.dll is loaded twice into
the appdomain.
Because both instances of the Plug1in.dll are loaded in the same appdomain
they each use the same proxy dll to access the web service. When a web
service call is made from the second instance of Plugin1.dll and which
returns a data type defined in Plugin1.dll the runtime throws an
exception. It cannot cast the return value to the type defined in the
second instance of Plugin1.dll because the proxy has that type as being
defined in the first instance of Plugin1.dll, so it treats them as two
different types.
There are several workarounds to this problem. The easy short-term fix was
to simply delete the Plugin1.dll that is in the Plugin2Dir - when the
runtime fails to locate it an AssemblyResolve event is triggered, so the
resolver can tell it to use the assembly in Plugin1Dir. This is not a
useful long-term solution because it is too fragile. One longterm solution
is to load each plugin into a separate appdomain - this means rewriting
and testing each one as all objects will have to be remoted from each
appdomain, but it is probably the way we will go. However, this does not
guarantee a fix in all cases because each plugin may itself do a LoadFrom
and/or have static references to other assemblies - the problem may be
recursive. Another is to have the app analyze all plugins and load those
with static references to other plugins first, but again the problem may
be recursive, so each plugin might have to implement similar logic.
Is there some way to override the default behavior of the runtime so that
it can be forced to use the path-based reference that is already loaded
into the appdomain instead of loading a second image of the assembly to
satisfy a static reference? The runtime does not generate the Resolve
event if it satisfies the reference request, so I cannot override the
static reference with the path-based reference because my code never gets
invoked.
My thought is that for assemblies signed with a strongname the runtime
could have a mode so that in cases where the full names of the assembly
match, a static reference is satisfied by a path based reference (and vice-
versa). Another is to add an event that allows code to get involved in the
static reference resolution process.
Thoughts? Any better way to handle this? and thanks in advance.
You can read messages from the Advanced DOTNET archive, unsubscribe from Advanced
DOTNET, or
subscribe to other DevelopMentor lists at http://discuss.develop.com.