So I have a WPF project that is pulling in dlls that are used by another project here at my job. It's a mess of dependencies, I've been using the technique here: http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application to embed the dependencies into a single executable.
Now, when I'm calling a specific method inside one of the dependencies, I hit the AssemblyResolve event. My OnResolveAssembly event runs, it finds the assembly as an embedded resource (cool!), and does "return Assembly.Load(assembyRawBytes)". If I hit F11 at this point (with a breakpoint at the beginning of OnResolveAssembly), I get another call into the same event. It's for the same assembly too (args.Name is the same).
If I let this run I hit a stack overflow, since I can never seem to escape this recursive event calling.
The MSDN docs don't really say when Assembly.Load can fail, except with a FileNotFoundException or BadImageFormatException.
I've tried unhooking the OnResolveAssembly at the moment before I call Assembly.Load, but then my application dies a mysterious death, even under VS it just goes poof.
I'm probably breaking several rules here, but some ideas of where to start looking for problems would be welcome.
I'm going to start poking around in the problematic DLL to see if there are hints about what is wrong with it (maybe it's a mixed assembly?).
Here's my OnResolveAssembly handler:
private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
AssemblyName assemblyName = new AssemblyName(args.Name);
string path = assemblyName.Name + ".dll";
if (assemblyName.CultureInfo.Equals(System.Globalization.CultureInfo.InvariantCulture) == false)
{
path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path);
}
using (Stream stream = executingAssembly.GetManifestResourceStream(path))
{
if (stream == null)
return null;
byte[] assemblyRawBytes = new byte[stream.Length];
stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
assemblyDictionary.Add(assemblyName.Name, Assembly.Load(assemblyRawBytes));
return assemblyDictionary[assemblyName.Name];
}
}
For the time being, I've resolved it by iterating through all of my resources and attempting Assembly.Load on them, and storing them in a dictionary for retrieval (during the OnResolveAssembly event):
[STAThread]
public static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
Assembly executingAssembly = Assembly.GetExecutingAssembly();
string[] resources = executingAssembly.GetManifestResourceNames();
foreach (string resource in resources)
{
if (resource.EndsWith(".dll"))
{
using (Stream stream = executingAssembly.GetManifestResourceStream(resource))
{
if (stream == null)
continue;
byte[] assemblyRawBytes = new byte[stream.Length];
stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
try
{
assemblyDictionary.Add(resource, Assembly.Load(assemblyRawBytes));
}
catch (Exception ex)
{
System.Diagnostics.Debug.Print("Failed to load: " + resource + " Exception: " + ex.Message);
}
}
}
}
App.Main();
}
private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
AssemblyName assemblyName = new AssemblyName(args.Name);
string path = assemblyName.Name + ".dll";
if (assemblyDictionary.ContainsKey(path))
{
return assemblyDictionary[path];
}
return null;
}
It seems be working fine now (the "failing" assembly will load fine in my second snippet), but I'd be interested to learn why it doesn't work in the first.