简体   繁体   English

从Word VBA调用DataTable.ReadXml在可编译库中不起作用

[英]DataTable.ReadXml not working in comvisible library when called from Word VBA

I'm trying to de-serialize an xml string into a DataTable. 我正在尝试将xml字符串反序列化为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." 当我从.NET(WinForms项目)中调用代码时,代码可以正常工作,但如果从Word VBA中调用代码,则会出现异常,提示“值不能为空”。

Just to be clear, my Winforms project is an Admin module and the COM visible library is my client. 需要明确的是,我的Winforms项目是一个管理模块,而COM可见库是我的客户端。 The Admin module do not have a reference to my COM library. 管理员模块没有对我的COM库的引用。 The COM library is mostly a wrapper for my other classes. COM库主要是我其他类的包装器。

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. 我的第一个想法当然是xml错误,所以我尝试在我的WinForms项目中使用一个硬编码的字符串,以便我知道它可以工作,然后在我的COM可见库中使用。 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. 我这样做是通过编写一些代码以使用硬编码字符串进行反序列化,然后从VBA调用该方法,但仍然失败。

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. 经过大量测试,我得出的结论是,它必须与从VBA调用的代码有关,以证明理论上我创建了一个新的测试WinForms项目,添加了对我的COM库的引用并以相同的方式运行代码我来自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. 最后一条信息是我在xml输入中有一个自定义类型。

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. 这在我的WinForms项目中起作用的原因是xml序列化器“知道”了DLL和类型,但是当从VBA调用时,序列化器无法找到/创建类型。 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. 注意:该类型已经在WinForms项目和COM库的代码中使用,因此对于任何一个项目都不是“未知”的。
  2. Somehow, when called from VBA the serializer uses a different Encoding which messes with the xml input. 不知何故,当从VBA调用时,序列化程序使用与XML输入混淆的另一种Encoding。

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". 我决定不包括xml输入,因为我已经确定它可以反序列化-另外,我只将它作为xml转义字符串,因此很难“理解”。

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. 如果您有任何疑问或需要更多信息,请随时提出。

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. 在调用DataTable.ReadXml之前进行测试时,我可以看到该程序集实际上已加载到AppDomain中,但是一旦进入System.Data库,则不再是从VBA调用的情况。

I suspect that the code inside the DataTable was actually running in the context of the Word AppDomain but i am not sure. 我怀疑DataTable中的代码实际上是在Word AppDomain的上下文中运行的,但我不确定。

The solution to all this is to resolve the assembly manually by hooking up to the AppDomain.CurrentDomain.AssemblyResolve and use the following code: 所有这些的解决方案是通过挂钩到AppDomain.CurrentDomain.AssemblyResolve并使用以下代码来手动解析程序集:

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. 我仍然对一种解释感兴趣,因此,如果有人有一个解释,我非常高兴:)另外,解决方案也不是很漂亮,因此,如果有人有更好的建议,请分享一下。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM