0

I'm trying to de-serialize an xml string into a DataTable. When i call the code from .NET (WinForms project) the code works perfectly but if i call the code from Word VBA i get an exception saying "Value cannot be null."

Just to be clear, my Winforms project is an Admin module and the COM visible library is my client. The Admin module do not have a reference to my COM library. The COM library is mostly a wrapper for my other classes.

at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.Data.Common.ObjectStorage.ConvertXmlToObject(XmlReader xmlReader, XmlRootAttribute xmlAttrib)
at System.Data.XmlDataLoader.LoadColumn(DataColumn column, Object[] foundColumns)
at System.Data.XmlDataLoader.LoadTable(DataTable table, Boolean isNested)
at System.Data.XmlDataLoader.LoadData(XmlReader reader)
at System.Data.DataTable.ReadXml(XmlReader reader, Boolean denyResolving)
at System.Data.DataTable.ReadXml(TextReader reader)

The following code is what i use to de-serialize the table.

var table = new DataTable();
using (var stringReader = new StringReader(tableXmlString))
  table.ReadXml(stringReader);

My first thought was of course that the xml was wrong so i tried using a hard coded string, first in my WinForms project so that i knew that it worked and then in my COM visible library. I did so by writing some code to de-serialize with the hard coded string and then call that method from VBA but it still failed.

After a lot of testing i came to the conclusion that it must have something to do with the code being called from VBA to prove that theory i created a new test WinForms project, added a reference to my COM library and ran the code the same way i did from VBA. As i expected there was no exception and de-serialization went fine.

One last piece of info is that i have a custom type that is in the xml input.

Speculation begins:

  1. The reason this is working in my WinForms project is that the DLL and type is "known" to the xml serializer but when calling from VBA somehow the serializer cannot find/create the type. note: The type is already being used in code in both the WinForms project and the COM library so it is not "unknown" to either project.
  2. Somehow, when called from VBA the serializer uses a different Encoding which messes with the xml input.

I decided not to include the xml input as i have already established that it can be de-serialized - Also i only have it as an xml escaped string making it difficult to "understand".

I hope someone can help me as i am getting very frustrated by this. If you have any questions or feel that you need more info, don't hesitate to ask.

Kenneth Lauritsen
  • 335
  • 1
  • 3
  • 11

1 Answers1

0

I never found the actual reason why this is happening but i have found a solution. It's not the prettiest solution but it works, and hopefully this will save someone else a lot of time.

I speculated that somehow the type could not be found, this is almost true. The actual problem was that the assembly containing my type, could not be found. When testing just before calling DataTable.ReadXml i could see that the assembly was in fact loaded into the AppDomain but once inside the System.Data library this was no longer the case if i was calling from VBA.

I suspect that the code inside the DataTable was actually running in the context of the Word AppDomain but i am not sure.

The solution to all this is to resolve the assembly manually by hooking up to the AppDomain.CurrentDomain.AssemblyResolve and use the following code:

System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
  try
  {
    var myType = typeof(MyType);
    var assembly = myType.Assembly;
    //Get the assembly name with comma. I do not care about version in this instance, but it is generally a good idea to include.
    //ex: MyTypeAssembly,
    var subString = assembly.FullName.Substring(0, assembly.FullName.IndexOf(',') + 1);
    if (args.Name.StartsWith(subString))
      return myType.Assembly;
  }
  catch
  {
    return null;
  }

  return null;
}

I am still interested in an explanation so if anyone has got one, i'm all ears :) Also, the solution isn't very pretty so if anyone has a better suggestion please share it.

Kenneth Lauritsen
  • 335
  • 1
  • 3
  • 11