How to Compile Source Code in .Net Dynamically ? | Generate Assembly Dynamically

 .Net Framework allows us to generate as well as compile our source code dynamically. We have already seen how we can generate the source code with the help of T4 Text Template in our previous post. Dynamic compilation is supported by .Net Framework with the help of CSharpCodeProvider class which is defined in the assembly System.CodeDom.dll.

Dynamic Compilation Using CSharpCodeProvider

In this post we will see how to use this class to compile our source code dynamically and generate an output assembly with an example. In our example we will create a Console Application in .Net Framework which uses CSharpCodeProvider to compile our source code using Compiler Parameters.

Sample Code

  • Defining source codes to be used for compilation: 
    • Below code is used in our sample application as input source files which will be used for compilation
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PetForm
{
    public class Pet
    {
        string name;
        string type;
        int age;

        public string Name { get { return name; } set { name = value; } }
        public string Type { get { return type; } set { type = value; } }
        public int Age { get { return age; } set { age = value; } }

        public Pet(string name, string type, int age)
        {
            this.name = name;
            this.type = type;
            this.age = age;
        }

        public void Walk()
        {
            Console.Write("I am Walking");
        }

        public void Talk()
        {
            Console.Write("I am Talking");
        }
    }

    class Cat : Pet
    {
        public Cat(string name, string type, int age) : base(name, type, age)
        {

        }
    }

    class Dog : Pet
    {
        public Dog(string name, string type, int age) : base(name, type, age)
        {

        }
    }
}

Once we have the input source file ready which in our case is pre created or else it can be generated dynamically using T4 Text templates or Code DOM. I have placed the source file in the Bin directory which is the default working directory when the Application runs.

  • Using CSharpCodeProvider to compile the Source code 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OnTheFlyCompilation
{
    internal class Program
    {
        static void Main(string[] args)
        {
            IList<string> arrCodes = new List<string>();
            foreach (var file in Directory.EnumerateFiles(@"D:\repos\OnTheFlyCompilation\bin\Debug\Source", "*.cs",SearchOption.AllDirectories))
            {
               var code =  File.ReadAllText(file);
               arrCodes.Add(code);
            }

            var assemblies = AppDomain.CurrentDomain.GetAssemblies()
                .Where(x=>x.Location != null)
                .Select(x=>x.Location);

            using (var codeProvider = new CSharpCodeProvider())
            {
                var compilerParams = new CompilerParameters();
                compilerParams.GenerateInMemory = true;
                compilerParams.ReferencedAssemblies.AddRange(assemblies.ToArray());
                compilerParams.OutputAssembly = "AutoGenerated.dll";
                var results = codeProvider.CompileAssemblyFromSource(compilerParams,arrCodes.ToArray());
                if(results.Errors.HasErrors)
                {
                    Console.WriteLine(results.Errors);
                }
                else
                {
                    Console.WriteLine("Compilation is successful");
                }
            }
        }
    }
}

As we can see from the above code that i am reading the source files as text and loading the necessary assemblies which are part of the current AppDomain.

Once its done CSharpCodeProvider instance is created and CompileAssemblyFromSource is called passing in the list of source files to be compiled. In the Compiler Parameters i have mentioned the OutputAssembly name which needs to be created as output. This will be present in the Bin directory of the current Application as shown in the below screen shot.

Output Assembly created using CodeDOM compiler

CompileAssemblyFromSource API returns Compiler Results which contains the result of the compilation, it exposes the list of Errors and Warnings which are generated during the compilation process which is helpful in resolving errors if any.




Comments

Popular posts from this blog

Creating RESTful Minimal WebAPI in .Net 6 in an Easy Manner! | FastEndpoints

Step By Step Guide to Detect Heap Corruption in Windows Easily

How to dynamically add Properties in C# .NET?