I want my application to be distributable as a single .exe file but I want to be able to get nice error reports with source code line numbers (the application simply se
I have used the following AssemblyResolve
handler and then embedding both dll
and pdb
of any assemblies. You could set this up as anything that runs first thing in the application before dependencies are needed.
private static void SetupEmbeddedAssemblyResolve()
{
// Based on http://blogs.msdn.com/b/microsoft_press/archive/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition.aspx
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
var name = args.Name;
var asmName = new AssemblyName(name);
// Any retargetable assembly should be resolved directly using normal load e.g. System.Core issue:
// http://stackoverflow.com/questions/18793959/filenotfoundexception-when-trying-to-load-autofac-as-an-embedded-assembly
if (name.EndsWith("Retargetable=Yes"))
{
return Assembly.Load(asmName);
}
var executingAssembly = Assembly.GetExecutingAssembly();
var resourceNames = executingAssembly.GetManifestResourceNames();
var resourceToFind = asmName.Name + ".dll";
var resourceName = resourceNames.SingleOrDefault(n => n.Contains(resourceToFind));
if (string.IsNullOrWhiteSpace(resourceName)) { return null; }
var symbolsToFind = asmName.Name + ".pdb";
var symbolsName = resourceNames.SingleOrDefault(n => n.Contains(symbolsToFind));
var assemblyData = LoadResourceBytes(executingAssembly, resourceName);
if (string.IsNullOrWhiteSpace(symbolsName))
{
Trace.WriteLine(string.Format("Loading '{0}' as embedded resource '{1}'", resourceToFind, resourceName));
return Assembly.Load(assemblyData);
}
else
{
var symbolsData = LoadResourceBytes(executingAssembly, symbolsName);
Trace.WriteLine(string.Format("Loading '{0}' as embedded resource '{1}' with symbols '{2}'", resourceToFind, resourceName, symbolsName));
return Assembly.Load(assemblyData, symbolsData);
}
};
}
private static byte[] LoadResourceBytes(Assembly executingAssembly, string resourceName)
{
using (var stream = executingAssembly.GetManifestResourceStream(resourceName))
{
var assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return assemblyData;
}
}