Assembly lookup , GAC and plugins

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Arnaud Debaene

    Assembly lookup , GAC and plugins

    Hello group.

    I have an app which can load "plugins" assemblies that are described
    in the registry (each registry entry gives the full path to the plugin
    ..dll file). The plugins may be anywhere on the disk.

    Each plugin defines a class which implements an interface known to the
    app. The main app loads the plugin with Assembly.LoadFr om and then
    uses Assembly.GetTyp es() and Type.FindInterf ace to find the concrete
    types in the plugin that implements the interface. An object of this
    concrete type is then constructed by reflection (ConstructorInf o ->
    Invoke).

    All of this is rather easy stuff. Now a plugin and the main app
    depends both on an utility assembly (let's call it Utils.dll).
    Utils.dll and MainApp.exe are strong-named, Plugin.dll is not.

    My problem is that the main app and the plugin are compiled at
    different times and therefore reference different versions of
    Utils.dll :
    MainApp.exe --> Utils.dll V 1.0.0.0
    Plugin.dll --> Utils.dll V 1.0.1.0

    Plugin.dll is in a directory unrelated to MainApp. Therefore, I must
    put Utils.dll V 1.0.1.0 in the GAC because Plugin.dll's path is not
    looked for when loading the plugin.

    Now, I can put Utils.dll v 1.0.0.0 either in MainApp directory, either
    in GAC. But in both cases, I got a FileNotFoundExc eption : "File or
    assembly name Utils, or one of its dependencies, was not found" when
    calling Assembly.LoadFr om("MyPlugin\Pl ugin.dll").
    It seems that, although Utils.dll is strong-named, since Utils.dll V
    1.0.0.0 is already loaded in the AppDomain, the GAC is not looked for
    the correct version of Utils (1.0.1.0) and therefore loading fails.

    Has anyone seen such a behaviour, and what would be the workaround?
    I've got no trace in fuslogvw (why??).


    Thanks,
    Arnaud
    MVP - VC

    PS : Utils.dll has no dependencies itself (except on the framework).
    There is no publishher file and no application configuration file
    (since plugins may be distributed after the app)
  • David Levine

    #2
    Re: Assembly lookup , GAC and plugins

    [color=blue]
    > My problem is that the main app and the plugin are compiled at
    > different times and therefore reference different versions of
    > Utils.dll :
    > MainApp.exe --> Utils.dll V 1.0.0.0
    > Plugin.dll --> Utils.dll V 1.0.1.0
    >
    > Plugin.dll is in a directory unrelated to MainApp. Therefore, I must
    > put Utils.dll V 1.0.1.0 in the GAC because Plugin.dll's path is not
    > looked for when loading the plugin.
    >
    > Now, I can put Utils.dll v 1.0.0.0 either in MainApp directory, either
    > in GAC. But in both cases, I got a FileNotFoundExc eption : "File or
    > assembly name Utils, or one of its dependencies, was not found" when
    > calling Assembly.LoadFr om("MyPlugin\Pl ugin.dll").
    > It seems that, although Utils.dll is strong-named, since Utils.dll V
    > 1.0.0.0 is already loaded in the AppDomain, the GAC is not looked for
    > the correct version of Utils (1.0.1.0) and therefore loading fails.
    >[/color]

    If the plugin is compiled against utils.dll, v1.0.0.0 and utils is signed
    with a strong name, then the runtime will load it if it can find it. As long
    as the assembly is signed the runtime can load two different versions of the
    same dll. The runtime can even load the same version of the dll twice, one
    in the Load context, and another copy in the LoadFrom context (although this
    is usually not what you want to happen).

    Have you tried signing the plugin.dll to see if this changes the behavior? I
    would not expect it too, but there may be other things going on.
    [color=blue]
    > Has anyone seen such a behaviour, and what would be the workaround?
    > I've got no trace in fuslogvw (why??).
    >
    >[/color]
    You can install a publisher policy for Utils.dll that specifies that the
    latest version of the dll should always be the one used - I don't know if
    this is what you want but it would avoid the problem you're seeing.

    Regardless, you could subscribe to the AssemblyResolve event and use that to
    manually locate the Utils.dll for the plugin.


    Comment

    • Arnaud Debaene

      #3
      Re: Assembly lookup , GAC and plugins

      "David Levine" <noSpamdlevineN NTP2@wi.rr.com> wrote in message news:<OXA#ZgBuE HA.2948@TK2MSFT NGP15.phx.gbl>. ..[color=blue][color=green]
      > > My problem is that the main app and the plugin are compiled at
      > > different times and therefore reference different versions of
      > > Utils.dll :
      > > MainApp.exe --> Utils.dll V 1.0.0.0
      > > Plugin.dll --> Utils.dll V 1.0.1.0
      > >
      > > Plugin.dll is in a directory unrelated to MainApp. Therefore, I must
      > > put Utils.dll V 1.0.1.0 in the GAC because Plugin.dll's path is not
      > > looked for when loading the plugin.
      > >
      > > Now, I can put Utils.dll v 1.0.0.0 either in MainApp directory, either
      > > in GAC. But in both cases, I got a FileNotFoundExc eption : "File or
      > > assembly name Utils, or one of its dependencies, was not found" when
      > > calling Assembly.LoadFr om("MyPlugin\Pl ugin.dll").
      > > It seems that, although Utils.dll is strong-named, since Utils.dll V
      > > 1.0.0.0 is already loaded in the AppDomain, the GAC is not looked for
      > > the correct version of Utils (1.0.1.0) and therefore loading fails.
      > >[/color]
      >
      > If the plugin is compiled against utils.dll, v1.0.0.0 and utils is signed
      > with a strong name, then the runtime will load it if it can find it. As long
      > as the assembly is signed the runtime can load two different versions of the
      > same dll.[/color]
      That's what I thaugt and that's why I don't understand the behaviour I
      get. I'm gonna do additionnal tests.
      [color=blue]
      > The runtime can even load the same version of the dll twice, one
      > in the Load context, and another copy in the LoadFrom context (although this
      > is usually not what you want to happen).[/color]
      What is exactly a Load Context? Ther is very few information on the
      subject. All I got in MSDN is KB 327435 (but this doesn't apply to
      ..NET 1.1 and VS2003, does it?) and the cryptic sentence in
      Assembly.Load documentation :
      "The Load methods use the default load context, which records the
      assembly name and assembly instance information for the set of
      assemblies that is the transitive closure of the assemblies referenced
      by a managed application" Huhhh????? How does it help with finding a
      new assembly?
      [color=blue]
      >
      > Have you tried signing the plugin.dll to see if this changes the behavior? I
      > would not expect it too, but there may be other things going on.[/color]
      I will try asap.
      [color=blue][color=green]
      > > Has anyone seen such a behaviour, and what would be the workaround?
      > > I've got no trace in fuslogvw (why??).
      > >
      > >[/color]
      > You can install a publisher policy for Utils.dll that specifies that the
      > latest version of the dll should always be the one used - I don't know if
      > this is what you want but it would avoid the problem you're seeing.[/color]


      [color=blue]
      > Regardless, you could subscribe to the AssemblyResolve event and use that to
      > manually locate the Utils.dll for the plugin.[/color]

      Now, this is interesting! I wasn't aware of this event. I will use it
      in my plugin loader mechanism. I could consider that all dependencies
      of a plugin are located in the plugin directory itself (which will
      also prevent me from clobbering the GAC with various versions of
      utils.dll).

      Thanks for the hints.

      Arnaud
      MVP - VC

      Comment

      • David Levine

        #4
        Re: Assembly lookup , GAC and plugins

        >> The runtime can even load the same version of the dll twice, one[color=blue][color=green]
        >> in the Load context, and another copy in the LoadFrom context (although
        >> this
        >> is usually not what you want to happen).[/color]
        > What is exactly a Load Context? Ther is very few information on the
        > subject. All I got in MSDN is KB 327435 (but this doesn't apply to
        > .NET 1.1 and VS2003, does it?) and the cryptic sentence in
        > Assembly.Load documentation :[/color]

        The KB article does not really address the Load versus LoadFrom context.

        What it boils down to is that the runtime's fusion layer keeps multiple
        internal lists of assemblies. Assemblies in the Load context can
        automatically bind to other assemblies in the Load context, and references
        to types defined in those assemblies can be resolved by the runtime without
        external assistance. Assemblies in the LoadFrom context cannot automatically
        bind to other assemblies in the LoadFrom context (at least, not as far as I
        know), and references to types must be manually resolved.

        What this means is that if Assembly a is in the LoadFrom context and it has
        a static reference to asm B (e.g. in the same directory as asm A but not
        loaded into fusion), then unless asm B is in a directory where fusion can
        locate it automatically (e.g. the GAC, or the appbase) it will not load, and
        will need to manually loaded by your own code (hence you need to hook the
        AssemblyResolve event).

        Further, if your code accesses a type defined in an assembly in the LoadFrom
        context, then when the runtime resolves that type it will have to access the
        assembly, but because it is not in the Load context it will generate another
        AssemblyResolve event even though the correct assembly is already loaded in
        the LoadFrom context.
        [color=blue]
        > "The Load methods use the default load context, which records the
        > assembly name and assembly instance information for the set of
        > assemblies that is the transitive closure of the assemblies referenced
        > by a managed application" Huhhh????? How does it help with finding a
        > new assembly?
        >[/color]
        That fancy terminology means something along the lines of loaded all
        required assemblies, including others referenced by other referenced
        assemblies. In other words, if loading asm A requires loading asm B and asm
        B requires asm C, then you wind up needing all 3 assemblies. If one is
        loaded in the Load context and it can resolve the transitive closure, then
        all 3 end up in the Load context.

        [color=blue][color=green]
        >> Regardless, you could subscribe to the AssemblyResolve event and use that
        >> to
        >> manually locate the Utils.dll for the plugin.[/color]
        >
        > Now, this is interesting! I wasn't aware of this event. I will use it
        > in my plugin loader mechanism. I could consider that all dependencies
        > of a plugin are located in the plugin directory itself (which will
        > also prevent me from clobbering the GAC with various versions of
        > utils.dll).[/color]

        If you are using LoadFrom then you absolutely need to become intimately
        familiar with that event. Simply putting the other assemblies in the same
        directory as where you loaded the other assembly does not guarantee that the
        runtime will look there for automatically loading other assemblies.


        Comment

        • Arnaud Debaene

          #5
          Re: Assembly lookup , GAC and plugins

          "David Levine" <noSpamdlevineN NTP2@wi.rr.com> wrote in message news:<uybE7nJuE HA.2640@TK2MSFT NGP10.phx.gbl>. ..
          <snip>
          Thank you for the detailed information!

          Arnaud
          MVP - VC

          Comment

          Working...