Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Debugging a generated .NET assembly from within the application that generated it

The question in short: How can I debug the code generated during a debugging session on the generating program? (see code below)

I am facing the following issue: I would like to debug into dynamically generated/compiled code from the application that generates it. I provided an oversimplified example to clarify it. This example doesn't need debugging! My real app generates many more lines and code that really justify debugging, believe me :-) I would like to know if there is a way to debug or put a breakpoint at HelloWorld. Stepping into the InvokeMethod call doesn't work. Maybe a solution involves code modification at the call sites to the generated assembly.

I had a look at many questions already (Debug dynamically loaded assembly in Visual Studio .NET for example) but none was helpful in solving the problem (if solvable at all?)

I took code from http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=118 as a base and fixed the obsoleted calls. Beside this I generated the assembly on-the-fly in memory and the calls are working well. I generated explicitly an assembly with Debug information, what gives me hope: why would there be the option if debugging is not possible?

using System;
using System.Text;
using System.IO;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;

namespace DynamicAssembly
{
    class CreateCompileExecute
    {
        [STAThread]
        static void Main(string[] args)
        {
            // Creates a text file to store the new class
            StringBuilder builder = new StringBuilder();
            builder.AppendLine("using System;");
            builder.AppendLine("namespace CSharpFriendsRocks");
            builder.AppendLine("{");
            builder.AppendLine("class CSharpFriends");
            builder.AppendLine("{");
            builder.AppendLine("public CSharpFriends() {" +
                " Console.WriteLine(\"The CSharpFriends type is constructed\"); }");
            builder.AppendLine("public void HelloWorld() {" +
                " Console.WriteLine(\"Hello World - CSharpFriends.Com Rocks.\"); }");
            builder.AppendLine("}");
            builder.AppendLine("}");

            // Create the C# compiler
            CSharpCodeProvider csCompiler = new CSharpCodeProvider();

            // input params for the compiler
            CompilerParameters compilerParams = new CompilerParameters();
            compilerParams.OutputAssembly = "CSharpFriends.dll";
            compilerParams.GenerateInMemory = true;
            compilerParams.IncludeDebugInformation = true;
            compilerParams.ReferencedAssemblies.Add("system.dll");
            compilerParams.GenerateExecutable = false; // generate the DLL

            // Run the compiler and build the assembly
            CompilerResults results = csCompiler.CompileAssemblyFromSource(
                compilerParams, builder.ToString());

            // Load the generated assembly into the ApplicationDomain 
            Assembly asm = results.CompiledAssembly;
            Type t = asm.GetType("CSharpFriendsRocks.CSharpFriends");

            // BindingFlags enumeration specifies flags that control binding and 
            // the way in which the search for members and types is conducted by reflection. 
            // The following specifies the Access Control of the bound type
            BindingFlags bflags = BindingFlags.DeclaredOnly | BindingFlags.Public
                        | BindingFlags.NonPublic | BindingFlags.Instance;

            // Construct an instance of the type and invoke the member method
            Object obj = t.InvokeMember("HelloWorld", bflags |
                BindingFlags.CreateInstance, null, null, null);

            // Call the method
            t.InvokeMember("HelloWorld", bflags | BindingFlags.InvokeMethod,
                    null, obj, null);
        }
    }
}
like image 996
jdehaan Avatar asked Oct 20 '09 11:10

jdehaan


People also ask

How do I debug an assembly file?

You start debugging by clicking Start Debugging on the Debug menu. On the Start Debugging dialog box, check Enable Assembler debugging, then click OK. If you debug the module again during the same session, you can start it by clicking Start Debugging, Run or Debug.

How do I decompile .NET assemblies?

To do this, go to the Modules window and from the context menu of a . NET assembly, and then select the Decompile source code command. Visual Studio generates a symbol file for the assembly and then embeds the source into the symbol file. In a later step, you can extract the embedded source code.


1 Answers

I finally found a way to workaround it after discovering that my question was a duplicate of How to debug/break in codedom compiled code, which was not obvious for me to find. bbmud gives a very good hint in there to get the debugger working correctly, but doesn't tell how to get into the code. I add a reference to some assembly containing an interface that I want to implement in the scripts:

compilerParams.ReferencedAssemblies.Add(typeof(IPlugin).Assembly.Location);
compilerParams.GenerateExecutable = false; // generate the DLL

// if you want to debug, this is needed...
compilerParams.GenerateInMemory = false;
compilerParams.TempFiles = new TempFileCollection(Environment.
      GetEnvironmentVariable("TEMP"), true);

Now when I consider CSharpFriends being an implementation of IPlugin, I can get the interface by casting the obj above:

IPlugin script = obj as IPlugin;

Then debugging calls to interface methods or properties is as easy as usual! The trick of adding

 System.Diagnostics.Debugger.Break();

inside the script code also works well but it needs change to the script. As the code inside the application always needs to know what kind of methods are inside the script according to some mechanism (reflexion with attributes or interfaces), using an interface known by both is a very acceptable solution for me.

I hope it helps somebody else.

like image 120
jdehaan Avatar answered Oct 17 '22 07:10

jdehaan