Showing posts with label CodeDom. Show all posts
Showing posts with label CodeDom. Show all posts

Sunday, May 2, 2010

Assembly on a fly

Recently I was on a project that needed me to create assemblies on a fly from source code contained on the disk in simple txt files.
The way to go was CodeDom way.

This blog is all about CodeDom. We will see how to generate the assembly in memory from a simple .cs/txt file containing n number of classes.
Lets for example we have simple .cs file having a single class.


Class MyClass
{

public int MyId
{
get;
set;

}

public string MyName
{
get;
set;
}

public string MySSNO
{
get;
set;

}

public MyClass(int id, string name, string ssno)
{
this.MyId = id;
this.MyName = name;
this.MySSNo = ssno;

}

}


We have this class in .cs file on disk.

Namespaces to use for in memory assembly creation are:-

using System.CodeDom.Compiler;
using System.CodeDom;
using Microsoft.CSharp;


These namespaces contains the classes that we will use to compile our code and create in memory assembly.

Lets start with initializing these classes.


CodeDomProvider provider = new
Microsoft.CSharp.CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
CompilerParameters parms = new CompilerParameters();


Now we will set the parameters for the compiler.

parms.GenerateExecutable = false;
parms.GenerateInMemory = true;
parms.IncludeDebugInformation = false;
parms.CompilerOptions = String.Format("/lib:\"{0}\"",
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Reference Assemblies\Microsoft\Framework\v3.0")) + String.Format(" /lib:\"{0}\"",
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Reference Assemblies\Microsoft\Framework\v3.5"));


If there are any assemblies that our code references we can add them as:-

parms.ReferencedAssemblies.Add("PresentationCore.dll");
parms.ReferencedAssemblies.Add("PresentationFramework.dll");
parms.ReferencedAssemblies.Add("System.dll");
parms.ReferencedAssemblies.Add("System.configuration.dll");
parms.ReferencedAssemblies.Add("System.Core.dll");
parms.ReferencedAssemblies.Add("System.Drawing.dll");
parms.ReferencedAssemblies.Add("System.Data.dll");
parms.ReferencedAssemblies.Add("System.XML.dll");
parms.ReferencedAssemblies.Add("WindowsBase.dll");


Next step is to read the .cs file content, i.e our source code.

string fileContent = string.Empty;
StreamReader reader = null;

using (FileStream csFileStream = new FileStream(filePath,
FileMode.Open, FileAccess.Read))
{
reader = new StreamReader(csFileStream);
fileContent = reader.ReadToEnd();
reader.Close();
}


After reading our source code as string , we will create a compile unit for out source code and compile it .

CodeCompileUnit compileUnit = new CodeSnippetCompileUnit
(fileContent);
CompilerResults results = compiler.CompileAssemblyFromDom(parms,
compileUnit);


We will check for any errors that came during the compilation.

//Report errors if any.
if (results.Errors.Count > 0)
{
CompilerErrorCollection errors = results.Errors;

for (int i = 0; i < errors.Count; i++ )
{
Console.WriteLine(errors[i].ErrorText.ToString());
}
}


if there are no errors during compilation , we have got our in memory assembly.

Assembly myIMemoryAssembly = results.CompiledAssembly;