How to use XmlSerializer with classes produced from CompileAssemblyFromSource ?

I dynamicaly generate code and use theCodeDomProviderandCompileAssemblyFromSourceto produce an in memory Assembly. The generated code uses List<T> as one of the Properties.

I then need to stream XML into and out of a class in the in memory Assembly.

I first use theActivator to create an instance of the class:

Assembly assembly = results.CompiledAssembly;

Type[] exportedTypes = assembly.GetExportedTypes();

object rc =Activator.CreateInstance(exportedTypes[0])

The next step is to put the object in a Property Grid and fill it with data.

So far so good.

The problem occurs when i try to use theXmlSerializer to write it out as XML:

StringWriter sw1 = new StringWriter();
Type type = rc.GetType();
XmlSerializer xs = new XmlSerializer(type, "Common.Generated");
try
{
using (XmlTextWriter writer = new XmlTextWriter(sw1))
{
writer.Formatting = Formatting.Indented;
xs.Serialize(writer, rc);
}
Log(sw1.ToString());

}
catch (Exception ex)
{
Log(ex.ToString());
}

I get the following exception:

System.InvalidOperationException: There was an error generating the XML document. > System.TypeInitializationException: The type initializer for 'Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterXXX' threw an exception. > System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterXXX..cctor()
End of inner exception stack trace
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterXXX..ctor()
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializerContract.get_Writer()
at System.Xml.Serialization.TempAssembly.InvokeWriter(XmlMapping mapping, XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
End of inner exception stack trace
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o)

If I cut and past the generated code into a simple Test Program it compiles and Serializes fine, using the same code from above.

Here is a sample of the Generated Code:

namespace Common.Generated
{
[Serializable()]
[XmlRoot("CONFIGURATION")]
public class XXX
{
[XmlInclude(typeof(XXX.ITEM))]
[XmlInclude(typeof(List<XXX.ITEM>))]
[Serializable()]
public class ITEM
{
public ITEM() { }

private string NameField = String.Empty;
[XmlElement("NAME")]
public string Name
{
get { return (this.NameField); }
set { this.NameField = value; }
}
}

public XXX() { }

private List<XXX.ITEM> items_ = new List<XXX.ITEM>();
[XmlArray("ITEMS")]
[XmlArrayItem("ITEM", Type=typeof(XXX.ITEM))]
public List<XXX.ITEM> Items
{
get { return ( this.items_ ); }
set { this.items_ = value; }
}
}
}

Here is a sample of how I am compiling the code:

CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters compilerParameters = new CompilerParameters();

compilerParameters.ReferencedAssemblies.Add("System.dll");
compilerParameters.ReferencedAssemblies.Add("mscorlib.dll");
compilerParameters.ReferencedAssemblies.Add("system.xml.dll");
compilerParameters.ReferencedAssemblies.Add("system.data.dll");
compilerParameters.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
compilerParameters.IncludeDebugInformation = false;
compilerParameters.GenerateExecutable = false;
compilerParameters.GenerateInMemory = true;

CompilerResults results = provider.CompileAssemblyFromSource(compilerParameters, _code);

if (results.Errors.HasErrors)
{
Log("Error compiling assembly:");
foreach (CompilerError error in results.Errors)
{
Log(error.ErrorText);
}
}
else
{
Assembly assembly = results.CompiledAssembly;
Type[] exportedTypes = assembly.GetExportedTypes();
rc = Activator.CreateInstance(exportedTypes[0]);
Log("OK");
}
}

Any help would be apprecieated...

[6476 byte] By [ogreboy] at [2007-12-26]
# 1

seems strange... i would set a break point at the beginning and step through... if you're getting

"Object reference not set to an instance of an object.
at "

Then most likely somewhere there is a variable not initialized and when you find out which one it is, it could give us a lot more idea where to go next. (maybe step through the initialization process of the object that's coming up null).

Debugger is your friend.

jhered at 2007-9-4 > top of Msdn Tech,.NET Development,XML and the .NET Framework...
# 2
Are you sure that

exportedTypes[0]

is the type you want? I doubt they appear in a predictable order and I believe the public nested class will also be exported.

DuncanWoods at 2007-9-4 > top of Msdn Tech,.NET Development,XML and the .NET Framework...
# 3

The Activator creates an instance of the correct class.

It is passed to a Property editor to Fill in the Items in the List and the Property Editor has no problem using the instance.

ogreboy at 2007-9-4 > top of Msdn Tech,.NET Development,XML and the .NET Framework...
# 4
Hmm yes, I have replicated the problem. I can't say what the precise problem is but I have a couple of workarounds either of which will work for you:

i) Don't nest the Item class
ii) Set GenerateInMemory to false.

Its curious since the compiler doesn't generate in memory even when asked (creates a dll in the temp folder) so no idea why this fixes the problem.

DuncanWoods at 2007-9-4 > top of Msdn Tech,.NET Development,XML and the .NET Framework...
# 5
Hi,

Has anyone found a solution to this problem except the workarounds? I'm mainly asking cause I need to generate the assembly in memory (though you say that it gets written anyway - wow) and I've got the exact same problem! I'm also asking cause I lost about 4 hours before I find this post, so if a solution is found it will at least be a compensation :):)

Thanx...

Mpellos at 2007-9-4 > top of Msdn Tech,.NET Development,XML and the .NET Framework...
# 6

Here is another thing that could help anyone that is actually trying to find a solution to this problem. The same serialization problem occurs not just when the assembly is dynamically compiled in memory, but also even if an assembly is loaded in memory using the Assembly.Load method that receives as input the byte form of the assembly file. So if you have an assembly with a class that contains a property that is a generic list of objects also defined in the assembly and you use the following code to load it :

System.IO.FileStream fs = new System.IO.FileStream(@"MyAssemblyPath\MyAssembly.dll", System.IO.FileMode.Open);

byte[] buffer = new byte[(int)fs.Length];

fs.Read(buffer, 0, buffer.Length);

fs.Close();

System.Reflection.Assembly assembly = Assembly.Load(buffer);

Then the same problem occurs when you try to use the XmlSerializer. So the problem is not the dynamic in-memory compilation but in general the use of an assembly that is loaded in memory.

Please, someone, try to find a solution to this...

Thanx...

Mpellos at 2007-9-4 > top of Msdn Tech,.NET Development,XML and the .NET Framework...
# 7

Ended up using previously mentioned workarounds.

No real answer to the problem though.

ogreboy at 2007-9-4 > top of Msdn Tech,.NET Development,XML and the .NET Framework...

.NET Development

Site Classified