Search code examples
wpfassembliesappdomaingac

Use different versions of the same class in host/plugin scenario


I have developed a WPF plugin-based application whereby plugin assemblies are dynamically loaded into a "host" application and both the host application and its plugins reference common assemblies.

If at some point in the future I wish to tweak a class of the common assembly, I don't want to have to recompile all of the plugins in order for them to work within a host application which might be running with a different version of common assemblies.

Scenario:

  • There are 2 versions of the common assemblies (1.1.0.0 and 1.2.0.0), signed and deployed the Global Assembly Cache. Each contains a class "Foo" which remains untouched between versions. Due to the architecture, Foo has to stay within the common assembly.
  • The host application is built against common version 1.1.0.0 and provides a base class from which view models within all plugins can derive; its function is very UI centric, so it has to stay within the host application.
  • Plugin #1 is built against common version 1.1.0.0
  • Plugin #2 is built against common version 1.2.0.0
  • Relevant third party components used: Microsoft's Prism and ServiceLocation and Castle (Windsor)

Common:

public class Foo
{
    // Some useful properties
}

Host:

public class ViewModelBase<T> where T : Foo
{
    // Some useful behaviour
}

Plugin #1:

public class ViewModel : ViewModelBase<Foo>
{

}

Plugin #2:

public class ViewModel : ViewModelBase<Foo>
{

}

ISSUE:

Upon loading Plugin #2, I receive a ReflectionTypeLoadException due to the fact that the Foo class of version 1.1.0.0 is not considered the same as the Foo class of version 1.2.0.0 and so using Foo as the type parameter for the view model in Plugin #2 is invalid.

IDEAS:

  • Using a more immutable "core" common assembly to contain the Foo class (but in the end, this would entail taking too many classes from too many different assemblies) and so isn't an option

  • Using assembly redirects (but forcing plugins to use the same version of common assemblies as the host application does not guarantee that a plugin that works during development will continue to work post-deployment, unless rules are put in place that ensure no breaking changes can be introduced using obsolescence attributes)

Has anyone managed to get a truly side-by-side (not to be confused with .NET framework side-by-side) scenario like this working (be it in single or multiple app domains)?


Thanks very much,

Rob


Solution

  • We ended getting around the issue using assembly redirects in the app.config file of the Host application.