Svante Seleborg
Oct 27, 2011
  26316
(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
Copy Optimizely SaaS CMS Settings to ENV Format Via Bookmarklet

Do you work with multiple Optimizely SaaS CMS instances? Use a bookmarklet to automatically copy them to your clipboard, ready to paste into your e...

Daniel Isaacs | Dec 22, 2024 | Syndicated blog

Increase timeout for long running SQL queries using SQL addon

Learn how to increase the timeout for long running SQL queries using the SQL addon.

Tomas Hensrud Gulla | Dec 20, 2024 | Syndicated blog

Overriding the help text for the Name property in Optimizely CMS

I recently received a question about how to override the Help text for the built-in Name property in Optimizely CMS, so I decided to document my...

Tomas Hensrud Gulla | Dec 20, 2024 | Syndicated blog

Resize Images on the Fly with Optimizely DXP's New CDN Feature

With the latest release, you can now resize images on demand using the Content Delivery Network (CDN). This means no more storing multiple versions...

Satata Satez | Dec 19, 2024

Simplify Optimizely CMS Configuration with JSON Schema

Optimizely CMS is a powerful and versatile platform for content management, offering extensive configuration options that allow developers to...

Hieu Nguyen | Dec 19, 2024

Useful Optimizely CMS Web Components

A list of useful Optimizely CMS components that can be used in add-ons.

Bartosz Sekula | Dec 18, 2024 | Syndicated blog