Pregunta

Lo que quiero lograr es muy simple:Tengo un Windows Forms (.NET 3.5) de la aplicación que utiliza una ruta de acceso para la lectura de la información.Esta ruta puede ser modificada por el usuario, mediante el formulario de opciones que ofrecen.

Ahora, quiero salvar el valor de la ruta a un archivo para su posterior uso.Este sería uno de los muchos ajustes guardados en este archivo.Este archivo se sentaba directamente en la carpeta de la aplicación.

Entiendo que hay tres opciones disponibles:

  • ConfigurationSettings archivo (nombre de aplicación.exe.config)
  • Registro
  • Archivo XML personalizado

He leído que el .NET archivo de configuración no está prevista para guardar los valores de volver a él.Como para el registro, me gustaría llegar tan lejos como sea posible.

¿Significa esto que debo usar un archivo XML personalizado para guardar los ajustes de configuración?Si es así, me gustaría ver el código de ejemplo de C#).

He visto en otros debates sobre este tema, pero todavía no está claro para mí.

¿Fue útil?

Solución

Si se trabaja con Visual Studio, a continuación, es bastante fácil de conseguir con persistencia de configuración.Haga clic derecho sobre el proyecto en el Explorador de soluciones, seleccione Propiedades.Seleccione la ficha Configuración, haga clic en el hipervínculo si los ajustes no existe.Utilice la ficha Configuración para crear una configuración de aplicación.Visual Studio crea los archivos Settings.settings y Settings.Designer.settings que contienen la clase singleton Settings heredado de ApplicationSettingsBase.Usted puede tener acceso a esta clase desde el código de lectura/escritura de la configuración de la aplicación:

Properties.Settings.Default["SomeProperty"] = "Some Value";
Properties.Settings.Default.Save(); // Saves settings in application configuration file

Esta técnica es aplicable tanto para la consola, Windows Forms y otros tipos de proyectos.

Tenga en cuenta que usted necesita para establecer el alcance propiedad de su configuración.Si selecciona el ámbito de la Aplicación, a continuación, Ajustes.Por defecto.< su propiedad > será de sólo lectura.

Otros consejos

Si planea guardar en un archivo dentro del mismo directorio que su ejecutable, aquí hay una buena solución que utiliza Formato JSON :

using System;
using System.IO;
using System.Web.Script.Serialization;

namespace MiscConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            MySettings settings = MySettings.Load();
            Console.WriteLine("Current value of 'myInteger': " + settings.myInteger);
            Console.WriteLine("Incrementing 'myInteger'...");
            settings.myInteger++;
            Console.WriteLine("Saving settings...");
            settings.Save();
            Console.WriteLine("Done.");
            Console.ReadKey();
        }

        class MySettings : AppSettings<MySettings>
        {
            public string myString = "Hello World";
            public int myInteger = 1;
        }
    }

    public class AppSettings<T> where T : new()
    {
        private const string DEFAULT_FILENAME = "settings.json";

        public void Save(string fileName = DEFAULT_FILENAME)
        {
            File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(this));
        }

        public static void Save(T pSettings, string fileName = DEFAULT_FILENAME)
        {
            File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(pSettings));
        }

        public static T Load(string fileName = DEFAULT_FILENAME)
        {
            T t = new T();
            if(File.Exists(fileName))
                t = (new JavaScriptSerializer()).Deserialize<T>(File.ReadAllText(fileName));
            return t;
        }
    }
}

El registro es un no-go. No está seguro de si el usuario que usa su aplicación tiene suficientes derechos para escribir en el registro.

Puede usar el archivo app.config para guardar configuraciones de nivel de aplicación (que son las mismas para cada usuario que usa su aplicación).

Almacenaría configuraciones específicas del usuario en un archivo XML, que se guardaría en Almacenamiento aislado o en SpecialFolder.ApplicationData directorio.

Además de eso, a partir de .NET 2.0, es posible almacenar valores de nuevo en el archivo <=>.

La clase ApplicationSettings no admite guardar configuraciones en el archivo app.config. Eso es en gran medida por diseño, las aplicaciones que se ejecutan con una cuenta de usuario debidamente protegida (piense en Vista UAC) no tienen acceso de escritura a la carpeta de instalación del programa.

Puedes luchar contra el sistema con la clase ConfigurationManager. Pero la solución trivial es ir al diseñador de Configuración y cambiar el alcance de la configuración a Usuario. Si eso causa dificultades (por ejemplo, la configuración es relevante para todos los usuarios), debe colocar su función de Opciones en un programa separado para que pueda solicitar la solicitud de elevación de privilegios. O renunciar a usar una configuración.

El argumento del registro / configurationSettings / XML todavía parece muy activo. Los he usado todos, ya que la tecnología ha progresado, pero mi favorito se basa en Sistema de Threed combinado con Almacenamiento aislado .

La siguiente muestra permite el almacenamiento de objetos denominados propiedades en un archivo en almacenamiento aislado. Tales como:

AppSettings.Save(myobject, "Prop1,Prop2", "myFile.jsn");

Las propiedades se pueden recuperar usando:

AppSettings.Load(myobject, "myFile.jsn");

Es solo una muestra, no sugiere las mejores prácticas.

internal static class AppSettings
{
    internal static void Save(object src, string targ, string fileName)
    {
        Dictionary<string, object> items = new Dictionary<string, object>();
        Type type = src.GetType();

        string[] paramList = targ.Split(new char[] { ',' });
        foreach (string paramName in paramList)
            items.Add(paramName, type.GetProperty(paramName.Trim()).GetValue(src, null));

        try
        {
            // GetUserStoreForApplication doesn't work - can't identify.
            // application unless published by ClickOnce or Silverlight
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
            using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Create, storage))
            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.Write((new JavaScriptSerializer()).Serialize(items));
            }

        }
        catch (Exception) { }   // If fails - just don't use preferences
    }

    internal static void Load(object tar, string fileName)
    {
        Dictionary<string, object> items = new Dictionary<string, object>();
        Type type = tar.GetType();

        try
        {
            // GetUserStoreForApplication doesn't work - can't identify
            // application unless published by ClickOnce or Silverlight
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
            using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
            using (StreamReader reader = new StreamReader(stream))
            {
                items = (new JavaScriptSerializer()).Deserialize<Dictionary<string, object>>(reader.ReadToEnd());
            }
        }
        catch (Exception) { return; }   // If fails - just don't use preferences.

        foreach (KeyValuePair<string, object> obj in items)
        {
            try
            {
                tar.GetType().GetProperty(obj.Key).SetValue(tar, obj.Value, null);
            }
            catch (Exception) { }
        }
    }
}

Quería compartir una biblioteca que he creado para esto. Es una pequeña biblioteca, pero una gran mejora (en mi humilde opinión) sobre los archivos .settings.

La biblioteca se llama Jot (GitHub) , aquí hay un viejo El artículo del Proyecto de Código que escribí al respecto.

Así es como lo usaría para realizar un seguimiento del tamaño y la ubicación de una ventana:

public MainWindow()
{
    InitializeComponent();

    _stateTracker.Configure(this)
        .IdentifyAs("MyMainWindow")
        .AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
        .RegisterPersistTrigger(nameof(Closed))
        .Apply();
}

El beneficio en comparación con los archivos .settings: Hay considerablemente menos código, y es mucho menos propenso a errores ya que solo necesita mencionar cada propiedad una vez .

Con un archivo de configuración, debe mencionar cada propiedad cinco veces: una vez cuando crea explícitamente la propiedad y cuatro veces más en el código que copia los valores de un lado a otro.

El almacenamiento, la serialización, etc. son completamente configurables. Cuando los objetos de destino son creados por un contenedor IOC, puede [conectarlo] [] para que aplique el seguimiento automáticamente a todos los objetos que resuelve, de modo que todo lo que necesita hacer para que una propiedad sea persistente es abofetear un atributo [Rastreable] en ella.

Es altamente configurable, puede configurar: - cuando los datos persisten y se aplican globalmente o para cada objeto rastreado - cómo se serializa - dónde está almacenado (por ejemplo, archivo, base de datos, en línea, almacenamiento aislado, registro) - reglas que pueden cancelar la aplicación / persistencia de datos para una propiedad

¡Confía en mí, la biblioteca es de primera categoría!

Una manera simple es usar un objeto de datos de configuración, guardarlo como un archivo XML con el nombre de la aplicación en la carpeta local y al iniciarlo, leerlo nuevamente.

Aquí hay un ejemplo para almacenar la posición y el tamaño de un formulario.

El objeto de datos de configuración está fuertemente tipado y es fácil de usar:

[Serializable()]
public class CConfigDO
{
    private System.Drawing.Point m_oStartPos;
    private System.Drawing.Size m_oStartSize;

    public System.Drawing.Point StartPos
    {
        get { return m_oStartPos; }
        set { m_oStartPos = value; }
    }

    public System.Drawing.Size StartSize
    {
        get { return m_oStartSize; }
        set { m_oStartSize = value; }
    }
}

Una clase de administrador para guardar y cargar:

public class CConfigMng
{
    private string m_sConfigFileName = System.IO.Path.GetFileNameWithoutExtension(System.Windows.Forms.Application.ExecutablePath) + ".xml";
    private CConfigDO m_oConfig = new CConfigDO();

    public CConfigDO Config
    {
        get { return m_oConfig; }
        set { m_oConfig = value; }
    }

    // Load configuration file
    public void LoadConfig()
    {
        if (System.IO.File.Exists(m_sConfigFileName))
        {
            System.IO.StreamReader srReader = System.IO.File.OpenText(m_sConfigFileName);
            Type tType = m_oConfig.GetType();
            System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
            object oData = xsSerializer.Deserialize(srReader);
            m_oConfig = (CConfigDO)oData;
            srReader.Close();
        }
    }

    // Save configuration file
    public void SaveConfig()
    {
        System.IO.StreamWriter swWriter = System.IO.File.CreateText(m_sConfigFileName);
        Type tType = m_oConfig.GetType();
        if (tType.IsSerializable)
        {
            System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
            xsSerializer.Serialize(swWriter, m_oConfig);
            swWriter.Close();
        }
    }
}

Ahora puede crear una instancia y utilizarla en los eventos de carga y cierre de su formulario:

    private CConfigMng oConfigMng = new CConfigMng();

    private void Form1_Load(object sender, EventArgs e)
    {
        // Load configuration
        oConfigMng.LoadConfig();
        if (oConfigMng.Config.StartPos.X != 0 || oConfigMng.Config.StartPos.Y != 0)
        {
            Location = oConfigMng.Config.StartPos;
            Size = oConfigMng.Config.StartSize;
        }
    }

    private void Form1_FormClosed(object sender, FormClosedEventArgs e)
    {
        // Save configuration
        oConfigMng.Config.StartPos = Location;
        oConfigMng.Config.StartSize = Size;
        oConfigMng.SaveConfig();
    }

Y el archivo XML producido también es legible:

<?xml version="1.0" encoding="utf-8"?>
<CConfigDO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <StartPos>
    <X>70</X>
    <Y>278</Y>
  </StartPos>
  <StartSize>
    <Width>253</Width>
    <Height>229</Height>
  </StartSize>
</CConfigDO>

No me gusta la solución propuesta de usar web.config o app.config. Intenta leer tu propio XML. Eche un vistazo a Archivos de configuración XML & # 8211; No más web.config .

Otras opciones, en lugar de usar un archivo XML personalizado, podemos usar un formato de archivo más fácil de usar: archivo JSON o YAML.

  • Si usa .NET 4.0 dinámico, esta biblioteca es realmente fácil de usar (serializar, deserializar, soporte de objetos anidados y salida de pedidos como desee + fusionando múltiples configuraciones en una) JsonConfig (el uso es equivalente a ApplicationSettingsBase)
  • Para la biblioteca de configuración .NET YAML ... No he encontrado una que sea tan fácil de usar como JsonConfig

Puede almacenar su archivo de configuración en múltiples carpetas especiales (para todos los usuarios y por usuario) como se detalla aquí Environment.SpecialFolder Enumeration y varios archivos (solo lectura predeterminada, por rol, por usuario, etc.)

Si elige usar múltiples configuraciones, puede fusionar esas configuraciones: por ejemplo, fusionando configuraciones para default + BasicUser + AdminUser. Puede usar sus propias reglas: la última anula el valor, etc.

" ¿Esto significa que debería usar un archivo XML personalizado para guardar la configuración? " No, no necesariamente Utilizamos SharpConfig para tales operaciones.

Por ejemplo, si el archivo de configuración es así

[General]
# a comment
SomeString = Hello World!
SomeInteger = 10 # an inline comment

Podemos recuperar valores como este

var config = Configuration.LoadFromFile("sample.cfg");
var section = config["General"];

string someString = section["SomeString"].StringValue;
int someInteger = section["SomeInteger"].IntValue;

Es compatible con .Net 2.0 y superior. Podemos crear archivos de configuración sobre la marcha y podemos guardarlos más tarde. Fuente: http://sharpconfig.net/ Github: https://github.com/cemdervis/SharpConfig

Espero que ayude.

Por lo que puedo decir, .NET admite configuraciones persistentes utilizando la función de configuración de aplicación integrada:

  

La función de Configuración de la aplicación de Windows Forms facilita la creación, el almacenamiento y el mantenimiento de las aplicaciones personalizadas y las preferencias del usuario en la computadora cliente. Con la configuración de la aplicación Windows Forms, puede almacenar no solo datos de la aplicación, como cadenas de conexión de base de datos, sino también datos específicos del usuario, como las preferencias de la aplicación del usuario. Con Visual Studio o el código administrado personalizado, puede crear nuevas configuraciones, leerlas y escribirlas en el disco, vincularlas a las propiedades de sus formularios y validar los datos de configuración antes de cargar y guardar.    - http://msdn.microsoft.com/en-us/library/k4s6c3a0 .aspx

A veces desea deshacerse de la configuración guardada en el archivo web.config o app.config tradicional. Desea un control más detallado sobre la implementación de sus entradas de configuración y el diseño de datos separados. O el requisito es permitir agregar nuevas entradas en tiempo de ejecución.

Puedo imaginar dos buenas opciones:

  • La versión fuertemente tipada y
  • La versión orientada a objetos.

La ventaja de la versión fuertemente tipada son los nombres y valores de configuración fuertemente tipados. No hay riesgo de mezclar nombres o tipos de datos. La desventaja es que se deben codificar más configuraciones, no se pueden agregar en tiempo de ejecución.

Con la versión orientada a objetos, la ventaja es que se pueden agregar nuevas configuraciones en tiempo de ejecución. Pero no tiene nombres y valores fuertemente tipados. Debe tener cuidado con los identificadores de cadena. Debe conocer el tipo de datos guardado anteriormente al obtener un valor.

Puede encontrar el código de ambas implementaciones completamente funcionales AQUÍ .

public static class SettingsExtensions
{
    public static bool TryGetValue<T>(this Settings settings, string key, out T value)
    {
        if (settings.Properties[key] != null)
        {
            value = (T) settings[key];
            return true;
        }

        value = default(T);
        return false;
    }

    public static bool ContainsKey(this Settings settings, string key)
    {
        return settings.Properties[key] != null;
    }

    public static void SetValue<T>(this Settings settings, string key, T value)
    {
        if (settings.Properties[key] == null)
        {
            var p = new SettingsProperty(key)
            {
                PropertyType = typeof(T),
                Provider = settings.Providers["LocalFileSettingsProvider"],
                SerializeAs = SettingsSerializeAs.Xml
            };
            p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
            var v = new SettingsPropertyValue(p);
            settings.Properties.Add(p);
            settings.Reload();
        }
        settings[key] = value;
        settings.Save();
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top