WPF: How to combine multiple assemblies into a single exe

At work, I am currently working on a small WPF app that we want to keep as a simple standalone exe. However, it has dependencies on several third-party assemblies: SharpZipLib, Unity, ServiceLocator, etc.

Microsoft has handy tool called ILMerge that merges multiple .NET assemblies into a single dll or exe. Unfortunately, it doesn’t support WPF applications, because of the way XAML is compiled.

Instead, you can use another approach — include all your referenced third-party assemblies as embedded resources of the exe:

public partial class App : Application
{
    private void OnStartup(object sender, StartupEventArgs e)
    {
        AppDomain.CurrentDomain.AssemblyResolve +=
            new ResolveEventHandler(ResolveAssembly);

        // proceed starting app...
    }

    static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
    {
        Assembly parentAssembly = Assembly.GetExecutingAssembly();

        var name = args.Name.Substring(0, args.Name.IndexOf(',')) + ".dll";
        var resourceName = parentAssembly.GetManifestResourceNames()
            .First(s => s.EndsWith(name));

        using (Stream stream = parentAssembly.GetManifestResourceStream(resourceName))
        {
            byte[] block = new byte[stream.Length];
            stream.Read(block, 0, block.Length);
            return Assembly.Load(block);
        }
    }
}

Whenever .NET can’t find a referenced assembly, it will call our code and we can provide an Assembly instance ourselves. Note this code expects a sane DLL-naming convention :)

Update: Dan Chambers just tweeted about an improved and expanded version of this approach that automatically embeds referenced assemblies, and adds the assembly resolve hook at an earlier point in the app startup process.

May 14, 2009

7 Comments

mojtaba on June 2, 2009 at 12:23 am.

It is a funny creative solution thanks Mr.

Omar Shahine on September 22, 2009 at 12:36 pm.

Awesome tip. Even better than ILMerge.

Markus on May 11, 2010 at 4:16 pm.

Hi Richard,

cool idea and it is working for me if I Add the following code at the beginning of the Load Resources handler:

if((bool)TryFindResource(args.Name) == true) {
return FindResource(args.Name) as Assembly;
}
But if I reference a style in App.xaml which is defined in a component loaded it is not wrking. because the OnStartup Event is fired after the Resources in the App.xaml are resolved… ???

Do you have any suggestions?

Nice greetings, Markus

Richard on May 11, 2010 at 4:36 pm.

Markus: OnStartup may be too late in the WPF application lifecycle. Try binding the event in the App constructor instead?

Markus on May 11, 2010 at 5:02 pm.

Richard: Thanks for your very quick response! I’l give it a try…

Markus on May 12, 2010 at 8:49 am.

Thanks again! It is working like a charm now!

A little sample solution can be downloaded and used (for free) on my blog… ( see http://blog.mahop.net/post/Merge-WPF-Assemblies.aspx )

Nice greetings from Germany,
Markus

Pz on October 1, 2010 at 10:33 am.

Hi, thanks a lot for that one! I am not sure, but when the same assembly demanded from different places, isn’t the resource being read several times? If yes, simple caching is way to go.

Anyway thanks for a cool idea ;-)

Leave Your Comment

Your email will not be published or shared. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>