Let\'s say a create an (executable) assembly in memory by compiling a code string. Then I want to serialize this assembly object into a byte array and then store it in a da
Here is my example:
public static byte[] SerializeAssembly()
{
var compilerOptions = new Dictionary<string, string> { { "CompilerVersion", "v4.0" } };
CSharpCodeProvider provider = new CSharpCodeProvider(compilerOptions);
CompilerParameters parameters = new CompilerParameters()
{
GenerateExecutable = false,
GenerateInMemory = false,
OutputAssembly = "Examples.dll",
IncludeDebugInformation = false,
};
parameters.ReferencedAssemblies.Add("System.dll");
ICodeCompiler compiler = provider.CreateCompiler();
CompilerResults results = compiler.CompileAssemblyFromSource(parameters, StringClassFile());
return File.ReadAllBytes(results.CompiledAssembly.Location);
}
private static Assembly DeserializeAssembyl(object fromDataReader)
{
byte[] arr = (byte[])fromDataReader;
return Assembly.Load(arr);
}
private string StringClassFile()
{
return "using System;" +
"using System.IO;" +
"using System.Threading;" +
"namespace Examples" +
"{" +
" public class FileCreator" +
" {" +
" private string FolderPath { get; set; }" +
" public FileCreator(string folderPath)" +
" {" +
" this.FolderPath = folderPath;" +
" }" +
" public void CreateFile(Guid name)" +
" {" +
" string fileName = string.Format(\"{0}.txt\", name.ToString());" +
" string path = Path.Combine(this.FolderPath, fileName);" +
" if (!File.Exists(path))" +
" {" +
" using (StreamWriter sw = File.CreateText(path))" +
" {" +
" sw.WriteLine(\"file: {0}\", fileName);" +
" sw.WriteLine(\"Created from thread id: {0}\", Thread.CurrentThread.ManagedThreadId);" +
" }" +
" }" +
" else" +
" {" +
" throw new Exception(string.Format(\"duplicated file found {0}\", fileName));" +
" }" +
" }" +
" }" +
"}";
}
A dirty trick to get the assembly bytes using reflection:
MethodInfo methodGetRawBytes = assembly.GetType().GetMethod("GetRawBytes", BindingFlags.Instance | BindingFlags.NonPublic);
object o = methodGetRawBytes.Invoke(assembly, null);
byte[] assemblyBytes = (byte[])o;
Explanation: at least in my sample (assembly was loaded from byte array) the assembly instance was of type "System.Reflection.RuntimeAssembly". This is an internal class, so it can be accessed only using reflection. "RuntimeAssembly" has a method "GetRawBytes", which return the assembly bytes.
An assembly is more conveniently represented simply as a binary dll file. If you think of it like that, the rest of the problems evaporate. In particlar, look at Assembly.Load(byte[])
for loading an Assembly
from binary. To write it as binary, use CompileAssemblyFromSource and look at the result's PathToAssembly - then File.ReadAllBytes(path)
to obtain the binary from the file.
System.Reflection.Assembly
is ISerializable
and can simply be serialized like so:
Assembly asm = Assembly.GetExecutingAssembly();
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, asm);
and deserialization is just as simple but call BinaryFormatter.Deserialize
instead.