write savesetting leer applicationsettings application c# application-settings applicationsettingsbase

leer - savesetting c#



FileNotFoundException en ApplicationSettingsBase (3)

Al depurar una aplicación, siempre aparece el siguiente error cuando Break on Exception está habilitado en Visual Studio. Esto realmente me está molestando, ya que trabajamos con break on exception. Lo curioso es que todavía funciona cuando continúo (se carga StringCollection).

El mensaje es:

No se pudo cargar el archivo o ensamblado ''System.XmlSerializers, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089'' o una de sus dependencias. El sistema no puede encontrar el archivo especificado.

Aquí está el código que está causando la excepción (diseñador generado)

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

Traté de crear una aplicación de prueba vacía que muestra el error, pero la excepción no ocurrió. Nuestro proyecto es enorme, por lo que es difícil encontrar la causa. Tal vez alguien en este sitio tenga una idea de cómo resolver esto.


Como esto realmente parece ser parte de la operación normal (ver también: XmlSerializer dando FileNotFoundException al constructor ), solo puedo ofrecer dos soluciones:

Deshabilite esta excepción específica: vaya a Depurar / Excepciones, haga clic en Agregar, escriba: Excepciones de C ++, Nombre: EEFileLoadException (si esta es la excepción que está viendo), desmarque la casilla de verificación Lanzada para esta excepción.

Cambie el tipo de configuración a la cadena y acceda a ella, por ejemplo, de esta manera:

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


Está atrapando demasiadas excepciones, System.XmlSerializer lanzará siempre esta excepción como parte de su operación normal, la misma clase la atrapará y manejará. Cambie las opciones de depuración para que solo capture sus excepciones, no las excepciones que son capturadas y manejadas dentro de las clases de .net de trabajo en equipo.


Solo una explicación de por qué se lanza esta excepción. Puede reproducir la excepción con esta aplicación de Windows Forms de ejemplo. Comience agregando una configuración llamada "Configuración" de tipo StringCollection. Haga clic en los puntos en la columna Valor e ingrese un par de cadenas. Haga que el código de clase de formulario se vea así:

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

Depurar + Excepciones, marque la casilla de verificación Lanzado para excepciones de CLR. Ejecute el formulario y ciérrelo, el depurador se detendrá cuando se produzca la excepción. La parte superior de la pila de llamadas se ve así:

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

Puede ver la clase XmlSerializer buscando un ensamblado que contenga el serializador XML para la clase StringCollection. El método LoadGeneratedAssembly se ve así con los bits aburridos eliminados:

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) { ... } .... }

Y Compiler.GetTempAssemblyName ():

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

Este GetTempAssemblyName es el malhechor en este caso. La clase StringCollection vive en el ensamblado System.dll, el método genera el nombre "System.XmlSerializers". Este método está diseñado para encontrar el ensamblaje para sus propias clases, el generado por Sgen.exe. Como WindowsApplication1.XmlSerializers.dll para su programa de ejemplo. Pero StringCollection es una clase en .NET Framework, el nombre del ensamblado que genera simplemente no es válido. En realidad, no existe un ensamblado "System.XmlSerializers.dll" en el marco.

Los informes de comentarios sobre este comportamiento en connect.microsoft.com se han cerrado con "Por diseño". Fue, los diseñadores originales consideraron que el costo de prevenir la excepción era demasiado alto y decidieron simplemente atrapar la excepción. Lo cual todo funciona bien, la excepción es atrapada. Lo ve por casualidad porque activó la casilla de verificación Lanzado en el cuadro de diálogo Depurar + Excepciones.

Hacer que el código de serialización Xml se comporte de manera diferente aquí no es una opción. Hubiera sido bastante fácil para ellos simplemente filtrar los tipos en el ensamblado System.dll, pero esa es una batalla potencialmente interminable, hay muchas más ensamblajes en el marco. Una solución alternativa es usar su propia clase para almacenar la configuración en lugar de usar una StringCollection.