Host and Add-ins --- sharing host assemblies

This is based on a private discussion with David Levine. But the scenario is generally applicable.

 

David has an application with the following deployment:

 

Application

            Common

            Plugin

                        Plugin1

                        Plugin2

 

The application loads one or more plugins at runtime. Each plugin is deployed to its own directory. At runtime, the application loads the plugin in its own separate appdomain for isolation, with the application base of the appdomain set to the plugin’s directory. Plugins use assemblies in its own directory, as well as shared assemblies residing in directory Common.

 

The question is, fusion will not probe anything outside of application base (minus GAC). So how do plugins locate the shared assemblies?

 

There are only limited ways to load assemblies outside of the application base.

  1. GAC
  2. Assembly.LoadFrom/Assembly.LoadFile
  3. Codebase hint

1. GAC

 

Given the deployment model, GAC isn’t possible.

 

2. Assembly.LoadFrom/LoadFile

 

Assembly.LoadFrom/LoadFile works. But it has two disadvantages:

  1. It puts the assembly into a different load context, which may not be desirable.
  2. It assumes the plugin knows the deployment layout of the host (specifically, where the host puts the shared assemblies), which may or may not be true.

3. Codebase hint

 

Codebase hint will only work for strongly named assemblies. But given a host/plugin design, this is probably not too much to ask.

 

3.1 App.config

 

Let’s assume no change to machine.config. We leave with the option of app.config.

 

The app.config is authored by the plugin developer. It can’t know where the application is installed at development time, which means the plugin developer can’t put codebase hint for the shared assemblies in app.config.

 

Fortunately the application knows where the shared assemblies are installed, and it controls how to activate the plugins. It is possible to do some trick to make 3) happen.

 

Upon installation, the application can prepare an app.config template, with codebase hint pointing to the right location for the shared assemblies. Before it creates the plug in appdomain, the host merges the template with the real app.config, and use the processed app.config to create the new domain. The plugin now automatically knows how to locate the shared assemblies, and those assemblies are loaded into the default load context.

 

3.2 Host.config

 

Another way to use codebase hint is host config. Host config is projected to every appdomain so there is no need to do the processing above. But host config has a drawback that codebase hint in host config won’t be honored unless there is a bingingRedirect and the bindingRedirect results in a different version. But we can still use some trick to make that happen.

 

We can build a special version of those shared assemblies. They have a version number of “major.minor.0.0”. All the plugins references the special version at development time. The released assemblies with the application have the real version number (like “major.minor.month.date”).

 

Upon installation, the application generates a host.config, with bindingRedirect of “major.minor.0.0” to “major.minor.month.date”, and codebase hint to the location of the deployed shared assemblies.

 

Now at runtime, without any work, the plugins can automatically resolve the shared assemblies in default load context.