I have an existing .NET 2.0 Win Forms solution that's deployed on the client. For the sake of this scenario, lets call it 'WinApp.exe'. WinApp.exe has a direct reference to a private assembly named 'Assembly.dll'. Assembly.dll has a direct reference to another assembly named 'Framework.dll'. Within Framework.dll is a type named 'IPlugIn'. Framework.dll is not strong-named, but the version of the assembly is 1.0. There is a class in Assembly.dll that implements IPlugIn from Framework.dll.
I have another .NET 2.0 Win Forms solution named 'Framework.exe'. This Win Forms project also has a direct reference to Framework.dll, which has the 'IPlugIn' type defined. Framework.dll is not strong-named, but the version of this assembly is 2.0. Bit for bit, 'IPlugIn' in Framework.dll v2 is identical to 'IPlugIn' in Framework.dll v1. The code in Framework.exe uses reflection to load the implementation of IPlugIn that's in WinApp:
AssemblyName an = AssemblyName.GetAssemblyName("C:\\Program Files\\WinApp\\Assembly.dll");
Assembly dll = Assembly.Load(an);
object o = Activator.CreateInstance(dll.GetType("WinApp.ClassThatImplementsIPlugIn"));
IPlugIn iPlugIn = o as IPlugIn;
So far, so good. This code works! Now here's the troublesome part. I need to assign a strong name to Framework.dll v2, so that it can be put in the GAC. However, WinApp and its dependent assemblies will not be redeployed - it must continue to use the same versions of assemblies that it's currently using. When I give Framework.dll v2 a strong name and recompile and run Framework.exe, when the above code executes I receive a "InvalidCastException" on line:
IPlugIn iPlugIn = o as IPlugIn;
I think I'm receiving this exception because now that one version of Framework.dll has a strong name, the runtime is treating the type "IPlugIn" as if it's a different type altogether. I need to know if there's any way to solve this issue. Again, the requirements are:
Thanks in advance!
Chad
The problem here is that both the strong named Framework
as the old Framework
assembly are loaded. .NET does not really care that both definitions of IPlugin
are the same. They are from a differend assembly so they are different (I am a little puzzled as why it will raise an InvalidCastException
as a cast like that will just returns null
if failed).
option A
One method to still use the class will be to use reflection but this might go a long way when more types hosted in Framework
come to play. all of these will need to be accessed using reflection.
You can create wrappers to hide the reflection using something like this:
public class PluginWrapper : IPlugin
{
object fObj;
PropertyInfo fNameProperty;
MethodInfo fGetOtherMethod;
public PluginWrapper(object o)
{
fObj = o;
fNameProperty = o.GetType().GetInterface("IPlugin").GetProperty("Name");
fGetOtherMethod = o.GetType().GetInterface("IPlugin").GetMethod("GetOther", new Type[] { typeof(string) });
}
public string Name
{
get { return (string)fNameProperty.GetValue(fObj, null); }
}
public IOther GetOther(string name)
{
object result = fGetOtherMethod.Invoke(fObj, new object[] { name });
if (result == null)
return null;
return new OtherWrapper(result);
}
}
Then you can use your object as following:
IPlugin iPlugIn = new PluginWrapper(o);
option B
I can think of another way. I am not sure if this a road you should go as it looks a lot of "hacking" in my eyes but i'll share it anyway and let you decide.
You can let the assembly load using a byte stream instead of AssemblyName. That way it will be unable to resolve the other Framework
assembly and giving you a change to break in on the AssemblyResolve
event:
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
Assembly dll = Assembly.Load(File.ReadAllBytes(@"C:\Program Files\WinApp\Assembly.dll"));
object o = Activator.CreateInstance(dll.GetType("WinApp.ClassThatImplementsIPlugIn"));
IPlugin iPlugIn = o as IPlugin;
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.Name.ToLower().StartsWith("framework,"))
return typeof(IPlugin ).Assembly;
return null;
}
This might be a little tricky as by that you will give .NET a promise that the assembly is compatible and that you are prepared to take the risk. If things are not compatible then problems might quickly start to arise.
Other options
There might maybe also be ways to solve the problem using bindingredirect
element in app.config
. I'm not really known with the details about how that works but might be worth looking into a bit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With