Is it possible to save a dynamic assembly to disk?
Asked Answered
D

4

10

I recently bought Ayende's book Building DSLs in Boo (buy it, read it, it's awesome) but I'm coming up against an implementation problem and I want to see what the generated code looks like. I would normally use reflector to look at the code but in this case the assemblies are dynamic and only in memory. Is there a way to save dynamic assemblies to disk so that I can reflect them?

EDIT / My Answer:

Wow, it took awhile to come back to this one. Unfortunately I left an important bit out from the original question.

Important Bit: I'm using Ayende's RhinoDSL library as he recommends in the book. I have access to the boo compiler in my subclass of DslEngine which looks like this:

public class JobEngine : DslEngine
{
    protected override void CustomizeCompiler(Boo.Lang.Compiler.BooCompiler compiler, Boo.Lang.Compiler.CompilerPipeline pipeline, string[] urls)
    {
        pipeline.Insert(1, new ImplicitBaseClassCompilerStep(typeof (JobBase), "Prepare", "JobLanguage", "log4net", "Quartz"));
    }
}

To change the least and get what I wanted I needed to add one line...

public class JobEngine : DslEngine
{
    protected override void CustomizeCompiler(Boo.Lang.Compiler.BooCompiler compiler, Boo.Lang.Compiler.CompilerPipeline pipeline, string[] urls)
    {
        compiler.Parameters.GenerateInMemory = false; // <--- This one.
        pipeline.Insert(1, new ImplicitBaseClassCompilerStep(typeof (JobBase), "Prepare", "JobLanguage", "log4net", "Quartz"));
    }
}

This caused the compiler to output the assembly to my ~\LocalSettings\Temp directory and then I could then reflect it. It's important to note that making that change caused the rest of the program to break (RhinoDSL could no longer find the assemblies in memory because I output them to disk), so this is only useful as a debugging tool.

Discriminating answered 13/1, 2010 at 16:24 Comment(2)
Use object XML serialization?!.Barye
do you create that assemblies through CodeDom?Vallation
N
5

Look up where BooCompiler is instantiated, change the pipeline from CompileToMemory to CompileToFile

Naturalize answered 26/1, 2010 at 2:14 Comment(1)
This is what ultimately led me to the answer I needed so 1 accept to you sir.Discriminating
S
4

Yes, the AssemblyBuilder class has a Save method for this purpose. You need to use the appropriate mode for this, which is most likely RunAndSave:

AssemblyBuilder builder =
    AppDomain.CurrentDomain.DefineDynamicAssembly(
        name, AssemblyBuilderAccess.RunAndSave);
// build assembly
builder.Save(path);
Sortilege answered 13/1, 2010 at 16:33 Comment(3)
The assembly is already built for me in memory by the Boo Compiler. So I don't have access to the builder...Discriminating
It's a dynamic assembly, and if it hasn't been saved and loaded from disk, should cast to AssemblyBuilder in that case.Sortilege
@David M: Hmm...when I cast and hit the save method I get an InvalidOperationException saying that it's been saved.Discriminating
D
1

There may be an easier way to do it, but if you don't mind using WinDbg you can save any loaded managed assembly from memory (WinDbg uses the term module, but it works for managed assemblies as well).

Use the !savemodule command with the address of the assembly. If you don't have the address use the lm vm command with the module name. Following that you get a regular DLL assembly, that you can inspect in Reflector.

Of course you may also just look at the IL code in memory.

Damiandamiani answered 13/1, 2010 at 16:33 Comment(0)
W
0

If you can get the Assembly at runtime.

i.e.

Assembly assembly = typeof(YourDynamicType).Assembly;

You can then cast this assembly into AssemblyBuilder and call the Save method.

AssemblyBuilder assemblyBuilder = (AssemblyBuilder)assembly;
assemblyBuilder.Save(yourPath);
Wifehood answered 13/1, 2010 at 16:33 Comment(1)
Actually the cast works, but when I run the save method it dies saying that the assembly has already been saved...Discriminating

© 2022 - 2024 — McMap. All rights reserved.