Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Ten artykuł pomaga rozwiązać problem polegający na tym, że serializacja spowoduje, że program obsługi rozpoznawania zestawów będzie wywoływany rekursywnie.
Oryginalna wersja produktu: .NET Framework 3.5 z dodatkiem Service Pack 1, 4.5
Oryginalny numer KB: 2756498
Objawy
Załóżmy, że masz klasę oznaczoną za pomocą atrybutu XmlSerializerAssembly , jak w poniższym przykładzie:
[Serializable, XmlRoot(ElementName="Bindings", IsNullable=false), XmlSerializerAssembly(AssemblyName="Contoso.ObjectLoaders.Bindings")]
public class Bindings
{
(...)
}
Wygenerowany zestaw jest podpisany i umieszczany w globalnej pamięci podręcznej zestawów (GAC) zamiast w folderze bin . Zaimplementujesz również procedurę obsługi dla AppDomain.AssemblyResolve zdarzeń i serializujesz wystąpienie klasy w metodzie procedury obsługi rozpoznawania zestawów w następujący sposób:
private static Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
// Some code here
var serializer = new XmlSerializer(typeof(Bindings));
// Some more code here
}
W tym scenariuszu serializacja spowoduje, że program obsługi rozpoznawania zestawów będzie wywoływany rekursywnie, co może spowodować przepełnienie stosu.
Przyczyna
Jest to zamierzone działanie. Zestawy z atrybutem XmlSerializerAssembly są ładowane z elementem Assembly.LoadWithPartialName(string), co spowoduje ponowne wywołanie OnResolveAssembly procedury obsługi.
Obejście 1. Usuwanie atrybutu XmlSerializerAssembly
Ta metoda uniemożliwi załadowanie zestawu przez Assembly.LoadWithPartialName(string)element .
Obejście 2. Pisanie bardziej niezawodnej procedury obsługi rozpoznawania zestawów
Jest to zalecane obejście i rozwiąże wszelkie problemy związane z rekursją. Poniższy przykład to prosty szablon kodu dla tego obejścia. Głównym pomysłem jest dodanie już rozwiązanych zestawów do listy ogólnej (współbieżna torba została wybrana, ponieważ jej wątkowy bezpieczny) i powrócić, jeśli zestaw jest już w trakcie rozwiązywania problemu.
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);
}
}