La serialización en un controlador OnAssemblyResolve puede provocar recursividad

Este artículo le ayuda a resolver el problema en el que la serialización hará que se llame de forma recursiva al controlador de resolución de ensamblados.

Versión del producto original:   .NET Framework 3.5 Service Pack 1, 4.5
Número KB original:   2756498

Síntomas

Suponga que tiene una clase marcada con el XmlSerializerAssembly atributo como en el ejemplo siguiente:

[Serializable, XmlRoot(ElementName="Bindings", IsNullable=false), XmlSerializerAssembly(AssemblyName="Contoso.ObjectLoaders.Bindings")]
public class Bindings
{
    (...)
}

El ensamblado generado se firma y se coloca en la caché global de ensamblados (GAC) en lugar de en la carpeta bin. También implementa un controlador para el evento y serializa una instancia de la clase en el método del controlador de resolución de AppDomain.AssemblyResolve ensamblados de la siguiente manera:

private static Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
    // Some code here
    var serializer = new XmlSerializer(typeof(Bindings));
    // Some more code here
}

En este escenario, la serialización hará que se llame de forma recursiva al controlador de resolución de ensamblados, lo que puede provocar un desbordamiento de pila.

Causa

Este comportamiento es una característica del diseño de la aplicación. Los ensamblados con XmlSerializerAssembly el atributo se cargan con , que Assembly.LoadWithPartialName(string) volverán a llamar al OnResolveAssembly controlador.

Solución alternativa 1: Quitar atributo XmlSerializerAssembly

Este método impedirá que el ensamblado se cargue mediante Assembly.LoadWithPartialName(string) .

Solución alternativa 2: Escribir un controlador de resolución de ensamblados más sólido

Es la solución alternativa recomendada y resolverá cualquier problema relacionado con la recursión. El siguiente ejemplo es una plantilla de código simple para esta solución alternativa. La idea principal es agregar los ensamblados ya resueltos a una lista genérica (se eligió el paquete simultáneo porque su subproceso es seguro) y devolver si el ensamblado ya está en proceso de resolución.

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);
    }
}

Referencias