0

I have a C# .Net 4.0 Application hosting a C++ ActiveX control utilizing a C++ DLL with CLR enabled. The DLL has the main function of loading the parameters for the OCX and uses XML.Serializer for this purpose.

This stack is working fine when all components are built in MS Visual Studio .Net 2003 and the C# Application running in .Net 1.1.

However, when the entire modules are migrated to VS2010 and the Application to .Net 4.0, I get the dreaded Xml.Serializer illegal cast exception because of the mismatched context.

The exception occurs at the 4th line:

FileStream* fs = __gcnew FileStream( filename, FileMode::Open );
XmlReader* reader = __gcnew XmlTextReader( fs );
XmlSerializer* serializer = __gcnew XmlSerializer( __typeof(MyClass) );
MyClass* obj = __try_cast<MyClass*>(serializer->Deserialize(reader)); 

Here's the exception statement:

[A]MyClass cannot be cast to [B]MyClass.
Type A originates from 'ParameterModule, Version=0.0.0.0, Culture=neutral,      PublicKeyToken=null' in the context 'Default'
at location 'C:\path\to\module\ParameterModule.dll'.
Type B originates from 'ParameterModule, Version=0.0.0.0, Culture=neutral,  PublicKeyToken=null' in the context 'LoadNeither'
at location 'C:\path\to\modu~\ParameterModule.dll'. 

at ParameterModule.ParaClass.execute_DeSerialize() Exception was thrown.

Please note that the 'LoadNeither' context has location path with the tilde (~) character. The 'Default' context has the full path.

The interop DLL for the ActiveX control is automatically generated by VS2010.

I wonder what causes the exception. Is it the mismatch in Path? I'm not sure, but I think the DLL was loaded only once.

Or is it the mismatch in context? If it is because of the context mismatch, how do we make sure the loading context for Interop modules like the C++ ActiveX controls? Or, can we specify Xml.Serializer to load the DLL containing the Serializing classes in the Default context?

I've looked everywhere and I could not find the solution. The more I comb the internet, the more this become a mystery to me. Thanks in advance.

4

2 回答 2

1

但我认为 DLL 只加载了一次

不,它被加载了两次。这就是问题所在,.NET 类型的标识不仅仅是名称空间 + 类型名称,它还包括从中加载它的程序集。这是一个 DLL Hell 对策,它确保您不能从具有冲突定义的不同 DLL 中多次加载相同的类型。

“LoadNeither”上下文是您问题的线索。您以某种不寻常的方式加载此程序集。这样做的常用方法是使用 Assembly.LoadFile(),这是一种非常危险的方法,只应在您故意不希望类型匹配的非常特殊的情况下使用。您应该始终使用 LoadFrom() 代替,但如果可以的话,您应该更喜欢 Load()。您通常可以通过将 DLL 放在正确的目录中或使用<probing>app.exe.config 文件中的元素来实现。

顺便说一句,获取版本 0.0.0.0 也不是很健康,[AssemblyVersion] 在 .NET 中非常重要。

于 2013-08-11T14:02:13.803 回答
0

很奇怪,但是当我们使用 static_cast 时并没有发生异常

MyClass* obj = static_cast<MyClass*>(serializer->Deserialize(reader)); 

虽然这个答案并不能真正解决模块被加载两次的问题,但这种解决方法可能会对那里的人有所帮助。

于 2013-08-13T10:35:32.940 回答