¿Cómo mantiene la configuración de user.config en diferentes versiones de ensamblaje en .net?

146

Básicamente, el problema es que cada vez que cambia la versión del ensamblaje (es decir, el usuario instala una nueva versión de la aplicación), todos sus ajustes se restablecen a los valores predeterminados (o más exactamente, se crea un nuevo archivo user.config en una carpeta con una versión diferente número como el nombre)

¿Cómo puedo mantener la misma configuración al actualizar versiones, ya que parece que no se recomienda utilizar archivos ini o el registro?

Cuando usamos Clickonce parecía que podía manejar esto, por lo que parece que debería poder hacerse, pero no estoy seguro de cómo hacerlo.

Davy8
fuente
Pregunta similar ?
Allen Rice
No, eso se refiere al valor predeterminado para no registrar un archivo en el control de versiones (o eso deduje) Esto se refiere a la configuración específica del usuario (Windows) para un usuario final
Davy8
Justo la pregunta que necesitaba, gracias :)
Binary Worrier
He publicado una posible solución en el siguiente hilo: stackoverflow.com/a/47921377/3223783 ¡ Espero que ayude!
dontbyteme
He publicado una posible solución en este hilo . ¡Espero que ayude!
dontbyteme

Respuestas:

236

ApplicationSettingsBase tiene un método llamado Upgrade que migra todas las configuraciones de la versión anterior.

Para ejecutar la fusión cada vez que publique una nueva versión de su aplicación, puede definir un indicador booleano en su archivo de configuración que por defecto sea verdadero. Nombre que UpgradeRequired o algo similar.

Luego, al inicio de la aplicación, verifica si el indicador está configurado y, si lo está, llama al método de actualización , establece el indicador en falso y guarda tu configuración.

if (Settings.Default.UpgradeRequired)
{
    Settings.Default.Upgrade();
    Settings.Default.UpgradeRequired = false;
    Settings.Default.Save();
}

Lea más sobre el método de actualización en MSDN . La versión GetPreviousVersion también puede valer la pena si necesita hacer una fusión personalizada.

Markus Olsson
fuente
2
Una pequeña pregunta, ¿qué constituye una nueva versión? ¿Alguna parte del número de 4 partes? Yo uso ClickOnce, ¿es un animal diferente?
Paladín refractado
44
¿Qué tipo de configuración debe ser UpgradeRequired ? appSettings, userSettingsO applicationSettings? Como configuración de usuario en Settings.Settings, una vez que se cambia por primera vez a false, nunca volverá a ser verdad. Una nueva versión no restablecerá un UpgradeRequired de nuevo a True.
dialex
44
@dialex Debe ser una configuración de usuario. Las configuraciones de tipo Aplicación son de solo lectura. Los nuevos números de versión hacen que la configuración se restablezca porque la configuración se almacena en una ruta específica de la versión.
Leonard Thieu
44
Creo que respondí mi propia pregunta. Si existe una versión anterior del archivo de configuración, copiará sus valores en la versión más nueva cada vez que se inicie la aplicación, ¡probablemente no lo que desea!
Hugh Jeffner el
1
Estoy un poco sorprendido de que esto no sea solo un comportamiento predeterminado; si la configuración de la aplicación es nula al inicio y encuentra una configuración previa, la carga.
SteveCinq
3

Sé que ha pasado un tiempo ... En una aplicación winforms, solo llame My.Settings.Upgrade()antes de cargarlas. Esto obtendrá la última configuración, ya sea la versión actual o una versión anterior.

tinlyx
fuente
2

Aquí está mi investigación en caso de que alguien más esté teniendo dificultades para migrar configuraciones que se han cambiado / eliminado. El problema básico es que GetPreviousVersion()no funciona si ha cambiado el nombre o eliminado la configuración en la nueva versión de su aplicación. Por lo tanto, debe mantener la configuración en su Settingsclase, pero agregarle algunos atributos / artefactos para que no la use inadvertidamente en el código en otro lugar, haciéndolo obsoleto. Una configuración obsoleta de muestra se vería así en VB.NET (se puede traducir fácilmente a C #):

<UserScopedSetting(),
DebuggerNonUserCode(),
DefaultSettingValue(""),
Obsolete("Do not use this property for any purpose. Use YOUR_NEW_SETTING_NAME instead."),
NoSettingsVersionUpgrade()>
Public Property OldSettingName() As String
  Get
    Throw New NotSupportedException("This property is obsolete")
  End Get
  Set
    Throw New NotSupportedException("This property is obsolete")
  End Set
End Property

Asegúrese de agregar esta propiedad al mismo espacio de nombres / clase que tiene la configuración de su aplicación. En VB.NET, esta clase se nombra MySettingsy está disponible en el Myespacio de nombres. Puede usar la funcionalidad de clase parcial para evitar que sus configuraciones obsoletas se mezclen con sus configuraciones actuales.

Todo el crédito a jsharrison por publicar un excelente artículo sobre este tema. Puede leer más detalles al respecto allí.

punto net
fuente
1

Aquí hay una variación de las soluciones presentadas aquí que encapsula la lógica de actualización en una clase abstracta de la que pueden derivarse las clases de configuración.

Algunas soluciones propuestas utilizan un atributo DefaultSettingsValue para especificar un valor que indica cuándo no se cargaron las configuraciones anteriores. Mi preferencia es simplemente usar un tipo cuyo valor predeterminado lo indique. Como beneficio adicional, ¿una fecha y hora? es útil información de depuración.

public abstract class UserSettingsBase : ApplicationSettingsBase
{
    public UserSettingsBase() : base()
    {
        // Accessing a property attempts to load the settings for this assembly version
        // If LastSaved has no value (default) an upgrade might be needed
        if (LastSaved == null)
        {
            Upgrade();
        }
    }

    [UserScopedSetting]
    public DateTime? LastSaved
    {
        get { return (DateTime?)this[nameof(LastSaved)]; }
        private set { this[nameof(LastSaved)] = value; }
    }

    public override void Save()
    {
        LastSaved = DateTime.Now;
        base.Save();
    }
}

Derivar de UserSettingsBase:

public class MySettings : UserSettingsBase
{
    [UserScopedSetting]
    public string SomeSetting
    {
        get { return (string)this[nameof(SomeSetting)]; }
        set { this[nameof(SomeSetting)] = value; }
    }

    public MySettings() : base() { }
}

Y úsalo:

// Existing settings are loaded and upgraded if needed
MySettings settings = new MySettings();
...
settings.SomeSetting = "SomeValue";
...
settings.Save();
jeff krueger
fuente
0

Si sus cambios en user.settings se realizan mediante programación, ¿qué tal mantener una copia de (solo) las modificaciones a user.settings en un archivo separado, por ejemplo, user.customized.settings?

Probablemente aún desee mantener y cargar la configuración modificada en user.settings también. Pero de esta manera, cuando instala una versión más reciente de su aplicación con su versión más reciente de user.settings, puede preguntarle al usuario si desea continuar usando sus configuraciones modificadas volviendo a copiarlas en los nuevos user.settings. Puede importarlos al por mayor, o ponerse más elegante y pedirle al usuario que confirme qué configuración desea seguir utilizando.

EDITAR: leí demasiado rápido sobre la parte "más precisa" acerca de las versiones de ensamblaje que causan la instalación de un nuevo user.settings en un nuevo directorio específico de la versión. Por lo tanto, la idea anterior probablemente no lo ayude, pero puede proporcionar algo de reflexión.

JMD
fuente
0

Así es como lo manejé:

public virtual void LoadSettings(ServiceFileFormBaseSettings settings = null, bool resetSettingsToDefaults = false)
{
    if (settings == null)
            return;

    if (resetSettingsToDefaults)
        settings.Reset();
    else
    {
        settings.Reload();

        if (settings.IsDefault)
            settings.Upgrade();
    }

    this.Size = settings.FormSize;

}

y en la clase de configuración, definí la propiedad IsDefault:

// SaveSettings always sets this to be FALSE.
// This will have the default value TRUE when first deployed, or immediately after an upgrade.
// When the settings exist, this is false.
//
[UserScopedSettingAttribute()]
[DefaultSettingValueAttribute("true")]
public virtual bool IsDefault
{
    get { return (bool)this["IsDefault"]; }
    set { this["IsDefault"] = value; }
}

En SaveSettings, configuro IsDefault en falso:

public virtual void SaveSettings(ServiceFileFormBaseSettings settings = null)
{
    if (settings == null) // ignore calls from this base form, if any
        return;

    settings.IsDefault = false;
    settings.FormSize = this.Size;
    settings.Save();
}
Ian
fuente