I gave up on the transient assembly solution and opted to write the
assembly to disk, then read it back again in hopes that I can use the
XmlSerializer to deserialize xml documents into objects dynamically
defined. I created a test windows form which I think should work but I
receive an error of the same nature when I try to deserialize...
Here is the code for the form:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Reflection;
using System.Reflection.Emit;
namespace DynamicTypeDeserializer
{
public class DTD : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btnDDT;
private System.ComponentModel.Container components = null;
public static byte[] GetAssemblyBytes(string filename)
{
System.IO.FileStream fs = new System.IO.FileStream(filename,
System.IO.FileMode.Open);
byte[] buffer = new byte[(int) fs.Length];
fs.Read(buffer, 0, buffer.Length);
fs.Close();
return buffer;
}
public static Assembly AssemblyResolver(object sender,
ResolveEventArgs args)
{
AppDomain domain = (AppDomain) sender;
EmitAssembly(domain);
byte[] rawAssembly = GetAssemblyBytes("DynMod.dll");
byte[] rawSymbolStore = GetAssemblyBytes("DynMod.pdb");
Assembly assembly = domain.Load(rawAssembly, rawSymbolStore);
return assembly;
}
public static void EmitAssembly(AppDomain domain)
{
AssemblyName aName = new AssemblyName();
aName.Name = "DynamicModulesAssembly";
AssemblyBuilder ab = domain.DefineDynamicAssembly(aName,
AssemblyBuilderAccess.Save);
ModuleBuilder mb = ab.DefineDynamicModule("DynMod", "DynMod.dll",
true);
System.Reflection.Emit.TypeBuilder tb =
mb.DefineType("Person",System.Reflection.TypeAttributes.Class|System.Reflection.TypeAttributes.Public);
System.Reflection.Emit.FieldBuilder fb =
tb.DefineField("Name",typeof(string),System.Reflection.FieldAttributes.Public);
System.Reflection.Emit.ConstructorBuilder cb =
tb.DefineDefaultConstructor(System.Reflection.MethodAttributes.Public);
tb.CreateType();
ab.Save("DynMod.dll");
}
public object DeserializeDynamicType()
{
AppDomain appdom = AppDomain.CurrentDomain; //AppDomain appdom =
System.Threading.Thread.GetDomain();
appdom.AssemblyResolve+=new ResolveEventHandler(AssemblyResolver);
object person=null;
System.Type personType;
try
{
// You must supply a valid fully qualified assembly name here.
System.Runtime.Remoting.ObjectHandle handle =
appdom.CreateInstance("DynamicModulesAssembly", "Person");
person = handle.Unwrap();
personType = person.GetType();
if (personType != null)
{
using (System.IO.FileStream fs = new
System.IO.FileStream(@"c:\person.xml",System.IO.FileMode.Open))
{
try
{
System.Xml.Serialization.XmlSerializer xs = new
System.Xml.Serialization.XmlSerializer(personType);
person = xs.Deserialize(fs);
}
catch (System.Exception ex)
{
System.Console.WriteLine(ex.Message);
/* ??? "Unable to generate a serializer for type Person from
assembly <Unknown>
* because the assembly may be dynamic. Save the assembly
and load it from
* disk to use it with XmlSerialization."
*
* >>> That is what I thought I was doing here ?!? I'm
confused.
*/
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return person;
}
public DTD()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.btnDDT = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnDDT
//
this.btnDDT.Location = new System.Drawing.Point(56, 64);
this.btnDDT.Name = "btnDDT";
this.btnDDT.Size = new System.Drawing.Size(176, 23);
this.btnDDT.TabIndex = 0;
this.btnDDT.Text = "Deserialize Dynamic Type";
this.btnDDT.Click += new System.EventHandler(this.btnDDT_Click);
//
// DTD
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.btnDDT);
this.Name = "DTD";
this.Text = "Dynamic Type Deserializer";
this.ResumeLayout(false);
}
#endregion
[STAThread]
static void Main()
{
Application.Run(new DTD());
}
private void btnDDT_Click(object sender, System.EventArgs e)
{
object person = this.DeserializeDynamicType();
string name = (string)
person.GetType().InvokeMember("Name",System.Reflection.BindingFlags.Public,null,person,null);
MessageBox.Show(name);
}
}
}