So, I have a WPF project that pulls out the DLLs that are used by another project here at my work. This is a mess of dependencies, I used the technique here: http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application to embed dependencies in one executable file.
Now, when I call a specific method inside one of the dependencies, I push the AssemblyResolve event. My OnResolveAssembly event occurs, it finds the assembly as an embedded resource (cool!) And returns "Assembly.Load (assemblyyRawBytes)". If I remove F11 at this point (with a breakpoint at the beginning of OnResolveAssembly), I get another call to the same event. This is for the same assembly too (args.Name is the same).
If I allow this run, I push the stack overflow, since I can never escape this recursive event call.
MSDN docs don't really say when Assembly.Load might fail, with the exception of a FileNotFoundException or BadImageFormatException.
I tried to disable OnResolveAssembly at that moment before I call Assembly.Load, but then my application dies a mysterious death, even under VS it just goes puff.
I will probably break a few rules here, but some ideas on where to start looking for problems will be welcome.
I'm going to start bothering with a problematic DLL to find out if there are any hints of what's wrong with it (maybe this is a mixed build?).
Here is 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];
}
}
Currently, I have resolved it by repeating all my resources and trying Assembly.Load on them and saving 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;
}
Everything seems to work fine now (the βfailedβ build will load in my second fragment), but I would be interested to know why it does not work in the first.