Die Serialisierung eines OnAssemblyResolve-Handlers kann rekursion verursachen
In diesem Artikel erfahren Sie, wie Sie das Problem beheben, bei dem die Serialisierung dazu führt, dass der Assemblyre resolver-Handler rekursiv aufgerufen wird.
Ursprüngliche Produktversion: .NET Framework 3.5 Service Pack 1, 4.5
Ursprüngliche KB-Nummer: 2756498
Symptome
Angenommen, Sie haben eine Klasse, die wie im folgenden Beispiel mit dem XmlSerializerAssembly
-Attribut gekennzeichnet ist:
[Serializable, XmlRoot(ElementName="Bindings", IsNullable=false), XmlSerializerAssembly(AssemblyName="Contoso.ObjectLoaders.Bindings")]
public class Bindings
{
(...)
}
Die generierte Assembly wird signiert und im globalen Assemblycache (GAC) statt im Ordner bin abgelegt. Sie implementieren auch einen Handler für AppDomain.AssemblyResolve
das -Ereignis und serialisieren eine instance der -Klasse in der Assembly-Resolverhandlermethode wie folgt:
private static Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
// Some code here
var serializer = new XmlSerializer(typeof(Bindings));
// Some more code here
}
In diesem Szenario führt die Serialisierung dazu, dass der Assemblyre resolver-Handler rekursiv aufgerufen wird, was zu einem Stapelüberlauf führen kann.
Ursache
Es handelt sich hierbei um ein beabsichtigtes Verhalten. Assemblys mit dem XmlSerializerAssembly
-Attribut werden mit Assembly.LoadWithPartialName(string)
geladen, wodurch der OnResolveAssembly
Handler erneut aufgerufen wird.
Problemumgehung 1: Entfernen des XmlSerializerAssembly-Attributs
Diese Methode verhindert, dass die Assembly von Assembly.LoadWithPartialName(string)
geladen wird.
Problemumgehung 2: Schreiben eines robusteren Assemblyauflösungshandlers
Dies ist die empfohlene Problemumgehung und behebt alle Probleme im Zusammenhang mit der Rekursion. Das folgende Beispiel ist eine einfache Codevorlage für diese Problemumgehung. Die Standard Idee besteht darin, die bereits aufgelösten Assemblys einer generischen Liste hinzuzufügen (der gleichzeitige Beutel wurde ausgewählt, weil er threadsicher ist) und zurückzugeben, wenn die Assembly bereits aufgelöst wird.
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);
}
}
References
Feedback
https://aka.ms/ContentUserFeedback.
Bald verfügbar: Im Laufe des Jahres 2024 werden wir GitHub-Issues stufenweise als Feedbackmechanismus für Inhalte abbauen und durch ein neues Feedbacksystem ersetzen. Weitere Informationen finden Sie unterFeedback senden und anzeigen für