Wednesday, May 9, 2012

Run-time assembly creation

There are times where you may need to generate Assembly dynamically at run-time.  The blog post shares some code for the same.

public CompilerResults Compile()
{
//Set the compiler options
var compilerOptions = new Dictionary<string, string>();
compilerOptions.Add("CompilerVersion", "v4.0");

CodeDomProvider compiler = new CSharpCodeProvider(compilerOptions);
CompilerParameters parameters = new CompilerParameters();
parameters.WarningLevel = 4;
parameters.TreatWarningsAsErrors = false;
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = false;
parameters.OutputAssembly = GetFileName();
parameters.IncludeDebugInformation = false;
if (RoleEnvironment.IsAvailable)
parameters.TempFiles = new TempFileCollection(RoleEnvironment.GetLocalResource("CompilerTempFiles").RootPath, false);

string baseDir = Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location);
baseDir = baseDir.Substring(0,
baseDir.LastIndexOf(Path.DirectorySeparatorChar));
baseDir = baseDir.Substring(0,
baseDir.LastIndexOf(Path.DirectorySeparatorChar));

//Add required assembly references of your code
string assemblyName;
foreach (string assembly in GetReferences())
{
string suffix = assembly.EndsWith(".exe") ? "" : ".dll";

assemblyName = assembly;
if (!assembly.StartsWith("System"))
{
if (assembly.IndexOf(".dll") > -1)
{
assemblyName = FindAssembly(baseDir, assembly);
suffix = "";
}
parameters.ReferencedAssemblies.Add(assemblyName + suffix);
}
else
{
var assemblyPath = (from assm
in AppDomain.CurrentDomain.GetAssemblies()
where assm.FullName.IndexOf(assemblyName + ",") > -1
select assm).FirstOrDefault();

if (assemblyPath == null)
{
throw new Exception("Unable to locate assembly: "
+ assemblyName + suffix);
}

parameters.ReferencedAssemblies.Add(assemblyPath.Location);
}
}

//Get your dynamic code
string Code = GetCodeText();

CompilerResults results = compiler.CompileAssemblyFromSource(
parameters, Code);

return results;
}





With dynamic code you must have some known interface, so that you can create the dynamic object of given interface to invoke the code.

public IKnownInterface GetTableServiceContext()
{
string assemblyPath = GetFileName();
if (!File.Exists(assemblyPath))
{
throw new FileNotFoundException(assemblyPath + " not found");
}

System.Reflection.Assembly assem = AppDomain.CurrentDomain.Load(
File.ReadAllBytes(assemblyPath));

Type queryType = assem.GetType("DynamicClassName");

return Activator.CreateInstance(queryType) as IKnownInterface;
}





We should be avoiding dynamic code generation and look for solutions like dependency injection, MEF frameworks.

Engineering Excellence

Engineering Excellence Having solid engineering process and tools in place help to improve the agility of the system. Here is the high-level...