Can I have my assembly reference any version of another assembly?
.net, .net-3.5, c#, c#-5.0
Solution
One workaround would be to use the AppDomain.AssemblyResolve event at runtime. This fires whenever the resolution of an assembly fails. You can use this to load a different version of an assembly to that which the CLR is trying to load.
I've added a very simple demo on GitHub here:
https://github.com/danmalcolm/AssemblyResolutionDemo
This is set up as follows:
The main application App.exe directly references assembly ThirdPartyLibrary.dll version 2.0.0.0.
It also references MyLibrary, which references an older version of ThirdPartyLibrary version 1.0.0.0.
The AppDomain.AssemblyResolve event is used to redirect to the version used by the application when version 1.0.0.0 fails to load
AssemblyResolve is handled as follows:
public static void Initialise()
{
AppDomain.CurrentDomain.AssemblyResolve += ResolveThirdPartyLibrary;
}
private static Assembly ResolveThirdPartyLibrary(object sender, ResolveEventArgs args)
{
// Check that CLR is loading the version of ThirdPartyLibrary referenced by MyLibrary
if (args.Name.Equals("ThirdPartyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=fbcbfac3e44fefed"))
{
try
{
// Load from application's base directory. Alternative logic might be needed if you need to
// load from GAC etc. However, note that calling certain overloads of Assembly.Load will result
// in the AssemblyResolve event from firing recursively - see recommendations in
// http://msdn.microsoft.com/en-us/library/ff527268.aspx for further info
var assembly = Assembly.LoadFrom("ThirdPartyLibrary.dll");
return assembly;
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
return null;
}
We need to bind to the event before ThirdPartyLibrary is loaded, hence the explicit Initialise method.
Note also that the event only fires when the resolution of an assembly fails. If the version of ThirdPartyLibrary referenced by MyClassLibrary (1.0.0.0) were available in the GAC, then it would be loaded successfully and AssemblyResolve wouldn't fire. There would then be 2 different versions in use.
I'm demonstrating here that this mechanism could be used, I'm not saying it's a good idea. There are several things you'd need to take into account based on the environment in which your app is running and how it is set-up / installed / maintained etc.
Problem
- I am developing a class library (`MyClassLibrary`). - I depend on a third party class library (`ThirdPartyClassLibrary`). - I need to use the same version of `ThirdPartyClassLibrary` as my users. e.g., if I set a static value in `ThirdPartyClassLibrary` the user needs to see that change. - Users of my class may be depending on any one of 4 different versions of `ThirdPartyClassLibrary`. - `ThirdPartyClassLibrary` is large, I do not want to distribute it with my software. - I have reflected on all 4 versions of `ThirdPartyClassLibrary` and validated that the things I will be doing with them are compatible across all versions (interfaces are the same, methods signatures are the same, etc.). - I need calls into `ThirdPartyClassLibrary` to be performant! I can't reflect on everything every time I need to call something. - `MyClassLibrary` will be loaded at runtime, so I can't expect users to mess with assembly binding redirects or other develop-time settings (or any settings at all, my users are resistant to doing anything). - I would like to benefit from compile-time checking of my code, so ideally no reflection at all. How can I write `MyClassLibrary` such that when it is loaded into the process everything works correctly with whichever version of `ThirdPartyClassLibrary` the user has loaded?