Serialization on an OnAssemblyResolve handler may cause recursion

Symptoms

Consider the following scenario. You have a class marked with the XmlSerializerAssembly attribute as in the following example:

[Serializable, XmlRoot(ElementName="Bindings", IsNullable=false), XmlSerializerAssembly(AssemblyName="Contoso.ObjectLoaders.Bindings")]
public class Bindings
{
(...)
}
The generated assembly is signed and placed in GAC instead of in the bin folder. You also implement a handler for AppDomain.AssemblyResolve event and you serialize an instance of the class in the assembly resolver handler method as follows:

private static Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{



// Some code here



var serializer = new XmlSerializer(typeof(Bindings));


// Some more code here



}
In this scenario, the serialization will cause the assembly resolver handler to be called recursively, which may result in a stack overflow.


Cause

This behavior is by design. Assemblies with the XmlSerializerAssembly attribute are loaded with Assembly.LoadWithPartialName(string), which will call the OnResolveAssembly handler again.


Workaround

To workaround this behavior, choose one of the following options:


Option 1: Remove XmlSerializerAssembly attribute from the class

This option will prevent the assembly from being loaded by Assembly.LoadWithPartialName(string)


Option 2: Write a more robust Assembly Resolve handler

This is the recommended workaround and will resolve any issues related to recursion. Following is a simple code template for this workaround. The main idea is to add the already resolved assemblies into a generic list (the concurrent bag was chosen because it is thread safe) and return if the assembly is already in the process of being resolved.

static ConcurrentBag<string> listOfAssemblies = new ConcurrentBag<string>();

private static Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
if (listOfAssemblies.Contains(args.Name))
{

// Already resolving this assembly, return now
return null;
}
try
{
listOfAssemblies.Add(args.Name);
// Add your handler code here

}
finally
{

// Assembly was handled, remove from list
listOfAssemblies.Remove(args.Name);
}
}

Propiedades

Id. de artículo: 2756498 - Última revisión: 12 sept. 2012 - Revisión: 1

Comentarios