c# - application - Práctica recomendada para guardar la configuración de la aplicación en una aplicación de Windows Forms
properties settings default c# using (13)
"¿Esto significa que debo usar un archivo XML personalizado para guardar las configuraciones?" No, no necesariamente. Usamos 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 guardarlos más tarde. Fuente: http://sharpconfig.net/ Github: https://github.com/cemdervis/SharpConfig
Espero que ayude.
Lo que quiero lograr es muy simple: tengo una aplicación Windows Forms (.NET 3.5) que usa una ruta para leer información. Esta ruta puede ser modificada por el usuario, utilizando el formulario de opciones que proporciono.
Ahora, quiero guardar el valor de la ruta en un archivo para su uso posterior. Esta sería una de las muchas configuraciones guardadas en este archivo. Este archivo se sentaría directamente en la carpeta de la aplicación.
Entiendo que hay tres opciones disponibles:
- Archivo ConfigurationSettings (appname.exe.config)
- Registro
- Archivo XML personalizado
Leí que el archivo de configuración .NET no está previsto para guardar los valores en él. En cuanto al registro, me gustaría alejarme lo más posible de él.
¿Esto significa 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 (C #).
He visto otras discusiones sobre este tema, pero aún no está claro para mí.
A veces desea deshacerse de las configuraciones guardadas en el archivo tradicional web.config o app.config. Desea un control más preciso sobre la implementación de las 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 mecanografiada 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 tienes nombres y valores fuertemente escritos. Hay que tener cuidado con los identificadores de cadena. Debe saber el tipo de datos guardado antes al obtener un valor.
Puede encontrar el código de ambas implementaciones totalmente funcionales HERE .
El argumento registry / configurationSettings / XML todavía parece muy activo. Los he usado todos, ya que la tecnología ha progresado, pero mi favorita se basa en el sistema de Threed combinado con Almacenamiento Aislado .
El siguiente ejemplo permite el almacenamiento de un objeto denominado propiedades en un archivo en almacenamiento aislado. Como:
AppSettings.Save(myobject, "Prop1,Prop2", "myFile.jsn");
Las propiedades pueden ser recuperadas usando:
AppSettings.Load(myobject, "myFile.jsn");
Es solo una muestra, no sugiere buenas 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) { }
}
}
}
El registro es un no-go. No está seguro de si el usuario que utiliza su aplicación tiene suficientes derechos para escribir en el registro.
Puede usar el archivo app.config
para guardar la configuración del nivel de la aplicación (que es la misma para cada usuario que usa su aplicación).
Almacenaría las configuraciones específicas del usuario en un archivo XML, que se guardaría en el almacenamiento aislado o en el directorio SpecialFolder.ApplicationData .
app.config
, a partir de .NET 2.0, es posible almacenar valores de nuevo en el archivo app.config
.
La clase ApplicationSettings
no admite guardar configuraciones en el archivo app.config. En gran medida, por su diseño, las aplicaciones que se ejecutan con una cuenta de usuario adecuadamente 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 cada usuario), 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 utilizar un ajuste.
No me gusta la solución propuesta de usar web.config
o app.config
. Intenta leer tu propio XML. Eche un vistazo a los archivos de configuración XML - 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: el archivo JSON o YAML.
- Si usa .NET 4.0 Dynamic, esta biblioteca es realmente fácil de usar (serializar, deserializar, admitir objetos anidados y ordenar la salida como desee + fusionar varias configuraciones en una) JsonConfig (el uso es equivalente a ApplicationSettingsBase)
- Para la biblioteca de configuración de .NET YAML ... no he encontrado una que sea tan fácil de usar como JsonConfig
Puede almacenar su archivo de configuración en varias carpetas especiales (para todos los usuarios y por usuario) como se enumera aquí. Enumeración de archivos de entorno especial y múltiples (solo lectura predeterminada, por rol, por usuario, etc.)
- Ejemplo para obtener la ruta de la carpeta especial: C # obtener la ruta de% AppData%
Si elige utilizar varias configuraciones, puede fusionar esas configuraciones: por ejemplo, fusionar configuraciones para predeterminadas + BasicUser + AdminUser. Puede usar sus propias reglas: la última anula el valor, etc.
Por lo que puedo decir, .NET soporta configuraciones persistentes usando la función de configuración de aplicaciones integrada:
La función Configuración de la aplicación de Windows Forms facilita la creación, el almacenamiento y el mantenimiento de las preferencias de usuario y las aplicaciones personalizadas en la computadora cliente. Con la configuración de la aplicación Windows Forms, puede almacenar no solo los datos de la aplicación, como las cadenas de conexión a la base de datos, sino también los datos específicos del usuario, como las preferencias de la aplicación. Con Visual Studio o 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 cargarlos y guardarlos. - http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx
Quería compartir una biblioteca que he construido para esto. Es una pequeña biblioteca, pero una gran mejora (IMHO) sobre los archivos .settings.
La biblioteca se llama Jot (GitHub) , aquí hay un antiguo artículo de The Code Project que escribí al respecto.
Así es como lo usaría para hacer 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 mucho menos código y es mucho menos propenso a errores, ya que solo necesita mencionar cada propiedad una vez .
Con los archivos de configuración, debe mencionar cada propiedad cinco veces: una vez que crea explícitamente la propiedad y cuatro veces más en el código que copia los valores de un lado a otro.
Almacenamiento, serialización, etc. son completamente configurables. Cuando utiliza la inversión de control , 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 pegar un atributo [Rastreable] en él.
Estoy escribiendo todo esto, porque creo que la biblioteca es de primera categoría, y me gustaría popularizarla :)
Si planea guardar en un archivo dentro del mismo directorio que su ejecutable, aquí tiene una buena solución que usa el 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;
}
}
}
Una forma sencilla 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 en el inicio, leerlo.
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 usarla 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>
Si trabajas con Visual Studio, es bastante fácil obtener configuraciones persistentes. Haga clic derecho en el proyecto en el Explorador de soluciones, elija Propiedades. Seleccione la pestaña Configuración, haga clic en el hipervínculo si la configuración no existe. Utilice la pestaña Configuración para crear la configuración de la aplicación. Visual Studio crea los archivos Settings.settings
y Settings.Designer.settings
que contienen los Settings
clase singleton heredados de ApplicationSettingsBase . Puede acceder a esta clase desde su código para leer / escribir 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 necesita establecer la propiedad de alcance de su configuración. Si selecciona Ámbito de aplicación, entonces Settings.Default. <Su propiedad> será de solo lectura.
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();
}
}