Skip to content

Instantly share code, notes, and snippets.

@CamelCaseName
Last active January 3, 2025 09:52
Show Gist options
  • Save CamelCaseName/07d96897a7547b83a9d0d658437ef746 to your computer and use it in GitHub Desktop.
Save CamelCaseName/07d96897a7547b83a9d0d658437ef746 to your computer and use it in GitHub Desktop.
Example of self embedded assembly extraction
using System.Reflection;
using System.Runtime.Loader;
namespace AssemblyTest
{
internal class AssemblyTest
{
static AssemblyTest()
{
SetOurResolveHandlerAtFront();
}
private static Assembly AssemblyResolveEventListener(object sender, ResolveEventArgs args)
{
if (args is null)
{
return null!;
}
string name = "AssemblyTest.Resources." + args.Name[..args.Name.IndexOf(',')] + ".dll";
using Stream? str = Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
if (str is not null)
{
var context = new AssemblyLoadContext(name, false);
string path = Path.Combine(Directory.GetParent(Assembly.GetExecutingAssembly()?.Location!)!.Parent!.FullName, "UserLibs", args.Name[..args.Name.IndexOf(',')] + ".dll");
FileStream fstr = new(path, FileMode.Create);
str.CopyTo(fstr);
fstr.Close();
str.Position = 0;
return context.LoadFromStream(str);
}
return null!;
}
private static void SetOurResolveHandlerAtFront()
{
BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic;
FieldInfo? field = null;
Type domainType = typeof(AssemblyLoadContext);
while (field is null)
{
if (domainType is not null)
{
field = domainType.GetField("AssemblyResolve", flags);
}
else
{
return;
}
if (field is null)
domainType = domainType.BaseType!;
}
MulticastDelegate resolveDelegate = (MulticastDelegate)field.GetValue(null)!;
Delegate[] subscribers = resolveDelegate.GetInvocationList();
Delegate currentDelegate = resolveDelegate;
for (int i = 0; i < subscribers.Length; i++)
currentDelegate = Delegate.RemoveAll(currentDelegate, subscribers[i])!;
Delegate[] newSubscriptions = new Delegate[subscribers.Length + 1];
newSubscriptions[0] = (ResolveEventHandler)AssemblyResolveEventListener!;
Array.Copy(subscribers, 0, newSubscriptions, 1, subscribers.Length);
currentDelegate = Delegate.Combine(newSubscriptions)!;
field.SetValue(null, currentDelegate);
}
}
}
@CamelCaseName
Copy link
Author

CamelCaseName commented Mar 5, 2024

Just add all DLLs you want to load internally into a folder in your csproject called resources. then set their "Build action" to embedded resource
this method can also be used to use specific assembly versions dynamically as we run before all other assembly resolvers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment