2010-08-16 3 views
28

Lors du débogage d'une application, j'obtiens toujours l'erreur suivante lorsque l'exception de rupture est activée dans Visual Studio. Cela m'embête vraiment, puisque nous travaillons avec break on exception. Ce qui est amusant, c'est que ça marche quand je continue (le StringCollection est chargé).FileNotFoundException dans ApplicationSettingsBase

Le message est:

Impossible de charger le fichier ou d'assemblage 'System.XmlSerializers, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089' ou une de ses dépendances. Le système ne peut pas trouver le fichier spécifié.

Voici le code qui est à l'origine l'exception (designer produit)

[global::System.Configuration.UserScopedSettingAttribute()] 
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 
public global::System.Collections.Specialized.StringCollection Mru { 
     get { 
      return ((global::System.Collections.Specialized.StringCollection)(this["Mru"])); 
     } 
     set { 
      this["Mru"] = value; 
     } 
    } 

J'ai essayé de créer une application de test vide qui montre l'erreur, mais l'exception ne se produisait pas. Notre projet est énorme et il est difficile de trouver la cause. Peut-être que quelqu'un sur ce site a une idée de comment résoudre ce problème.

Répondre

51

Juste une explication de pourquoi cette exception est levée. Vous pouvez reproduire l'exception avec cet exemple d'application Windows Forms. Commencez par ajouter un paramètre nommé "Setting" de type StringCollection. Cliquez sur les points dans la colonne Valeur et entrez quelques chaînes. Faites ressembler le code de classe de formulaire comme ceci:

public partial class Form1 : Form { 
    public Form1() { 
     InitializeComponent(); 
    } 
    protected override void OnFormClosing(FormClosingEventArgs e) { 
     Properties.Settings.Default.Setting[0] = DateTime.Now.ToString(); 
     Properties.Settings.Default.Save(); 
     base.OnFormClosing(e); 
    } 
} 

Déboguer + Exceptions, cochez la case Thrown pour les exceptions CLR. Exécutez le formulaire et fermez-le, le débogueur s'arrêtera lorsque l'exception est levée. Le haut de la pile d'appel ressemble à ceci:

mscorlib.dll!System.Reflection.Assembly.nLoad(System.Reflection.AssemblyName fileName, string codeBase, System.Security.Policy.Evidence assemblySecurity, System.Reflection.Assembly locationHint, ref System.Threading.StackCrawlMark stackMark, bool throwOnFileNotFound, bool forIntrospection) + 0x2c bytes 
mscorlib.dll!System.Reflection.Assembly.InternalLoad(System.Reflection.AssemblyName assemblyRef, System.Security.Policy.Evidence assemblySecurity, ref System.Threading.StackCrawlMark stackMark, bool forIntrospection) + 0x80 bytes 
mscorlib.dll!System.Reflection.Assembly.Load(System.Reflection.AssemblyName assemblyRef) + 0x1d bytes 
System.Xml.dll!System.Xml.Serialization.TempAssembly.LoadGeneratedAssembly(System.Type type = {Name = "StringCollection" FullName = "System.Collections.Specialized.StringCollection"}, string defaultNamespace = null, out System.Xml.Serialization.XmlSerializerImplementation contract = null) + 0xcd bytes 
System.Xml.dll!System.Xml.Serialization.XmlSerializer.XmlSerializer(System.Type type = {Name = "StringCollection" FullName = "System.Collections.Specialized.StringCollection"}, string defaultNamespace = null) + 0x105 bytes 

Vous pouvez voir la chasse de classe XmlSerializer pour un ensemble qui contient le sérialiseur XML pour la classe StringCollection. La méthode LoadGeneratedAssembly ressemble à ceci avec les trépans enlevés:

internal static Assembly LoadGeneratedAssembly(Type type, string defaultNamespace, out XmlSerializerImplementation contract) 
{ 
    ... 
    AssemblyName parent = GetName(type.Assembly, true); 
    partialName = Compiler.GetTempAssemblyName(parent, defaultNamespace); 
    parent.Name = partialName; 
    parent.CodeBase = null; 
    parent.CultureInfo = CultureInfo.InvariantCulture; 
    try 
    { 
     serializer = Assembly.Load(parent);  // <=== here 
    } 
    catch (Exception exception) 
    { 
     ... 
    } 
    .... 
} 

Et Compiler.GetTempAssemblyName():

internal static string GetTempAssemblyName(AssemblyName parent, string ns) 
{ 
    return (parent.Name + ".XmlSerializers" + (((ns == null) || (ns.Length == 0)) ? "" : ("." + ns.GetHashCode()))); 
} 

Ce GetTempAssemblyName est le malfaiteur dans ce cas. La classe StringCollection vit dans l'assembly System.dll, la méthode génère le nom "System.XmlSerializers". Cette méthode est conçue pour trouver l'assembly pour vos propres classes, celui généré par Sgen.exe. Comme WindowsApplication1.XmlSerializers.dll pour votre exemple de programme. Mais StringCollection est une classe dans le .NET Framework, le nom de l'assembly qu'il génère n'est pas valide. Il n'y a pas réellement de "System.XmlSerializers".dll "assembly dans le cadre

Les rapports d'évaluation de ce comportement sur connect.microsoft.com ont tous été fermés avec" By Design ", les concepteurs d'origine ont estimé que le coût de la prévention de l'exception était trop élevé et ont décidé de L'exception est en effet attrapée, mais vous l'avez vu parce que vous avez activé la case à cocher Thrown dans la boîte de dialogue Debug + Exceptions

Le code de sérialisation Xml se comporte différemment Il aurait été assez facile pour eux de filtrer simplement les types dans l'assembly System.dll, mais c'est une bataille potentiellement interminable, il y a beaucoup plus d'assemblages dans le framework. classe pour stocker le paramètre à la place d'utiliser un StringCollection.

+0

Merci pour l'explication détaillée. J'essaie d'éviter d'utiliser StringCollection dans le futur. Dommage c'est "par conception". – testalino

+0

Là vous allez :) – testalino

+0

Brillante réponse encore une fois ... – MoonKnight

1

Vous rencontrez trop d'exceptions, le System.XmlSerializer lancera toujours cette exception dans le cadre de son fonctionnement normal, il est intercepté et géré par la classe elle-même. Changez vos options de débogage pour attraper seulement vos exceptions, pas les exceptions qui sont attrapées et manipulées dans les classes .net farmework.

+1

ick .... vraiment? – kenny

+1

+1, oui. J'ai une bonne dose de haine pour System.Xml, pas une des grandes parties. –

+0

Comme je l'ai dit, l'exception ne se produit pas avec la même propriété de paramètres dans une application de test. Il n'est donc pas vrai que XmlSerializer lève toujours cette exception. – testalino

6

Comme cela semble vraiment faire partie du fonctionnement normal (voir aussi: XmlSerializer giving FileNotFoundException at constructor), je ne peux offrir deux solutions de contournement:

Désactiver cette exception spécifique: goto Debug/Exceptions, cliquez sur Ajouter, tapez: C++ Exceptions, Name: EEFileLoadException (si c'est l'exception que vous voyez), décochez la case Thrown pour cette exception.

Modifiez le type du paramètre en chaîne et accédez-y, par ex. comme ceci:

var mru = Settings.Default.Mru.Split('|'); 
Settings.Default.Mru = string.Join("|", mru.ToArray()); 
Questions connexes