November Happy Hour will be moved to Thursday December 5th.

Svante Seleborg
Oct 27, 2011
  26213
(0 votes)

The type initializer for '<Module>' threw an exception

This post describes a rather obscure problem, and its solution, that occurred when we upgraded to ImageVault 3.5.4 with .NET 4.0 and EPiServer CMS 6 R2.

For once, I don’t quite understand all that happens, or rather why, but I’m hoping someone better versed than me can comment on it. Also since we did fix the issue, it may help others with similar problems and not necessarily tied to EPiServer or ImageVault. LeadTools is likely the key component here, which is used by ImageVault, but the situation as such is pretty generic and may pop up in any number of situations where cross AppDomain calls occur.

For readability, I’m showing the actual stack trace at the bottom of this post.

In brief, what seems to happen is that an AppDomain transition is indirectly caused by the call to ImageVault.ImageConverter(). I have not had the time to figure just what code is running in the other AppDomain, or why it needs to. But, the problem is, that when a cross AppDomain call is made, objects attached to the thread needs to be marshaled or serialized across. This is typically done by serialization. The fault we’re seeing is caused by the receiving AppDomain needing a reference to all types needed for deserialization, and it might not have access to the ASP.NET bin folder. This is the case here.

We’re using a custom IPrincipal object, here called Axantum.Identity, which obviously is attached to the thread, and thus gets serialized. But it can’t be deserialized in the other AppDomain, because there it can’t get at our custom type implementing IPrincipal there.

The solution is either to place the assemblies containing the types that needs to get serialized into the GAC, or to use marshaling by having the type in question derive from MarshalByRefObject . We wrapped our IPrincipal implementation inside another decorator that did derive from MarshalByRefObject as well as changed some component types to derive from MarshalByRefObject and problem was solved. We choose not to install into the GAC although that should work as well. I’m not entirely sure about any caveats or performance issues caused by using marshaling by reference instead of serialization – comments appreciated.

Here’s the stack trace, for reference:

ImageStoreNET.WS.Ajax.AjaxEditImageService.GetImageByName - Error converting image (ImageStoreNET.WS.Ajax.AjaxEditImageService) System.TypeInitializationException: The type initializer for '<Module>' threw an exception. ---> System.TypeInitializationException: The type initializer for '<Module>' threw an exception. ---> <CrtImplementationDetails>.ModuleLoadException: The C++ module failed to load while attempting to initialize the default appdomain.
---> System.Runtime.Serialization.SerializationException: Unable to find assembly 'Axantum.Identity, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
 
Server stack trace:
   at System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo assemblyInfo, String name)
   at System.Runtime.Serialization.Formatters.Binary.ObjectMap..ctor(String objectName, String[] memberNames, BinaryTypeEnum[] binaryTypeEnumA, Object[] typeInformationA, Int32[] memberAssemIds, ObjectReader objectReader, Int32 objectId, BinaryAssemblyInfo assemblyInfo, SizedArray assemIdToAssemblyTable)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryObjectWithMapTyped record)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryHeaderEnum binaryHeaderEnum)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Remoting.Channels.CrossAppDomainSerializer.DeserializeObject(MemoryStream stm)
   at System.Runtime.Remoting.Messaging.SmuggledMethodCallMessage.FixupForNewAppDomain()
   at System.Runtime.Remoting.Channels.CrossAppDomainSink.DoDispatch(Byte[] reqStmBuff, SmuggledMethodCallMessage smuggledMcm, SmuggledMethodReturnMessage& smuggledMrm)
   at System.Runtime.Remoting.Channels.CrossAppDomainSink.DoTransitionDispatchCallback(Object[] args)
 
Exception rethrown at [0]:
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at System.AppDomain.get_Id()
   at <CrtImplementationDetails>.DoCallBackInDefaultDomain(IntPtr function, Void* cookie)
   at <CrtImplementationDetails>.LanguageSupport.InitializeDefaultAppDomain(LanguageSupport* )
   at <CrtImplementationDetails>.LanguageSupport._Initialize(LanguageSupport* )
   at <CrtImplementationDetails>.LanguageSupport.Initialize(LanguageSupport* )
   --- End of inner exception stack trace ---
   at <CrtImplementationDetails>.ThrowModuleLoadException(String errorMessage, Exception innerException)
   at <CrtImplementationDetails>.LanguageSupport.Initialize(LanguageSupport* )
   at .cctor()
   --- End of inner exception stack trace ---
   at <CrtImplementationDetails>.ThrowModuleLoadException(String , Exception )
   at <CrtImplementationDetails>.LanguageSupport.Initialize(LanguageSupport* )
   at .cctor()
   --- End of inner exception stack trace ---
   at ImageConverterService.ImageConverter..ctor()
   at ImageConverterService.ImageConverterService.LoadDataObjectFormatInformation(String fullFilename)
   at ImageStoreNET.Classes.Data.DataFactory.LoadDataObjectFormatInformation(FileInfo file)
   at ImageStoreNET.Classes.Data.DataObjectFormatInformation.Load(FileInfo file)
   at ImageStoreNET.Classes.Data.DataFactory.GetImageInformation(FileInfo file)
   at ImageStoreNET.Classes.Util.ImageUtil.GetImageInformation(String filename, Boolean temp)
   at ImageStoreNET.WS.Ajax.AjaxEditImageService.GetImageInfo(String filename)
   at ImageStoreNET.WS.Ajax.AjaxEditImageService.GetImageByName(String filename, Boolean isUndo, String clientSideUndoScript, Int32 applicationMode2, Int32 dataObjectID)

Oct 27, 2011

Comments

Oct 31, 2011 03:21 PM

The marshaling in this case occurs since Leadtools is an unmanaged dll (dotnet C++ dll). Managed an unmanaged code cannot share memory so to communicate between those worlds we need to transfer parameters, return values and other data to the other side. This is what causes the cross app domain calls and the marshaling of your IPrincipal.

Regarding your question about serializing your data or using MarshalByRefObject I would think (I'm no expert in this field, I'm only guessing) that if the object don't get accessed much (properties/methods) then the MarshalByRefObject would be the fastest since you don't have to serialize/deserialize the object. If communication with the object is large (which it probably isn't in this case) then the serialization way would perhaps be fastest. To facilitate the communication between the appdomains, proxy classes are used and each call takes some amount of time.
All depends on the type of object and what communication that needs to take place.

As you stated, this is not a Leadtools specific problem, it applies to all calls between unmanaged and managed (or COM) code.

For more reading on the subject, the following articles can be a good start.
An Overview of Managed/Unmanaged Code Interoperability
http://msdn.microsoft.com/en-us/library/ms973872.aspx
Marshaling between Managed and Unmanaged Code
http://msdn.microsoft.com/en-us/magazine/cc164193.aspx

Svante Seleborg
Svante Seleborg Oct 31, 2011 04:23 PM

Thanks!

When you say it, it's of course obvious that unmanaged code must run separately. I was under the impression after a quick peek that Leadtools was C++/CLI, and without being any kind of expert I thought that transition would be benign and do run in the same AppDomain.

I doubt that the IPrincipal instance is ever really used after the transition and if it is it's not large, so I'll stick with the MarshalByRefObject solution until further notice.

Anyway, it's an important lesson to learn, and thanks for the clarification about Managed/Unmanaged interop.

Please login to comment.
Latest blogs
Optimizely SaaS CMS + Coveo Search Page

Short on time but need a listing feature with filters, pagination, and sorting? Create a fully functional Coveo-powered search page driven by data...

Damian Smutek | Nov 21, 2024 | Syndicated blog

Optimizely SaaS CMS DAM Picker (Interim)

Simplify your Optimizely SaaS CMS workflow with the Interim DAM Picker Chrome extension. Seamlessly integrate your DAM system, streamlining asset...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Optimizely CMS Roadmap

Explore Optimizely CMS's latest roadmap, packed with developer-focused updates. From SaaS speed to Visual Builder enhancements, developer tooling...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Set Default Culture in Optimizely CMS 12

Take control over culture-specific operations like date and time formatting.

Tomas Hensrud Gulla | Nov 15, 2024 | Syndicated blog

I'm running Optimizely CMS on .NET 9!

It works 🎉

Tomas Hensrud Gulla | Nov 12, 2024 | Syndicated blog

Recraft's image generation with AI-Assistant for Optimizely

Recraft V3 model is outperforming all other models in the image generation space and we are happy to share: Recraft's new model is now available fo...

Luc Gosso (MVP) | Nov 8, 2024 | Syndicated blog