how to serialize/deserialize an assembly object to and from a byte array

a 夏天 提交于 2019-11-28 04:51:58

问题


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 database. Then later on I want to retrieve the byte array from the database and deserialize the byte array back into an assembly object, then invoke the entry point of the assembly.

At first I just tried to do this serialization like I would any other simple object in .net, however apparently that won't work with an assembly object. The assembly object contains a method called GetObjectData which gets serialization data necessary to reinstantiate the assembly. So I'm somewhat confused as to how I piece all this together for my scenario.

The answer only needs to show how to take an assembly object, convert it into a byte array, convert that back into an assembly, then execute the entry method on the deserialized assembly.


回答1:


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.




回答2:


A dirty trick to get the assembly bytes using reflection:

  MethodInfo pi = assembly.GetType().GetMethod("GetRawBytes", BindingFlags.Instance | BindingFlags.NonPublic);
  object o = pi.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 be accessed only using reflection. "RuntimeAssembly" has a method "GetRawBytes", which return the assembly bytes.




回答3:


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));" +
      "         }" +
      "     }" +
      " }" +
      "}";
    }



回答4:


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.



来源:https://stackoverflow.com/questions/7629799/how-to-serialize-deserialize-an-assembly-object-to-and-from-a-byte-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!