如何在.net 中保持不同程序集版本之间的 user.config 设置?

基本上问题在于每次程序集版本改变(例如用户安装新版本的应用程序) ,所有的设置都会重置默认值(或者更准确地说,一个新的 user.config 文件被创建在一个名称为不同版本号的文件夹中)

升级版本时如何保持相同的设置,因为似乎不鼓励使用 ini 文件或注册表?

当我们使用 Clickonce 时,它似乎能够处理这个问题,所以它似乎应该能够做到,但我不确定如何做到。

39151 次浏览

ApplicationSettingsBase 有一个 称为升级的方法,它从以前的版本迁移所有设置。

为了在发布应用程序的新版本时运行合并,可以在设置文件中定义一个默认为 true 的布尔标志。命名为 升级需要或类似的东西。

然后,在应用程序启动时,检查是否设置了标志,如果设置了,调用 升级方法,将标志设置为 false 并保存配置。

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

MSDN上阅读更多关于 Upgrade 方法的内容。如果您需要进行一些自定义合并,那么 获取上一版本也值得一看。

如果您对 user.sets 的更改是通过编程完成的,那么在一个单独的文件(例如 user.customized.sets)中维护(仅)对 user.sets 的修改的副本如何?

您可能还需要维护和加载 user.sets 中修改过的设置。但是这样,当您使用较新版本的 user.sets 安装较新版本的应用程序时,您可以通过将修改后的设置复制回新的 user.sets 来询问用户是否希望继续使用这些设置。您可以批量导入它们,或者让用户确认他们希望继续使用哪些设置。

编辑: 关于汇编版本会导致一个新的 user.setup 被安装到一个新的版本特定的目录,我对“更准确”这一部分读得太快了。因此,上面的想法可能对你没有帮助,但是可以提供一些思考的食物。

我是这么处理的:

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;

}

在设置类中,我定义了 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; }
}

在 SaveSettings 中,我将 IsDefault 设置为 false:

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

我知道已经有一段时间了。 在 winform 应用程序中,只需在加载之前调用 My.Settings.Upgrade()即可。这将获得最新的设置,无论是当前版本还是以前版本。

以下是我的研究结果,以防其他人在迁移已更改/删除的设置时遇到困难。基本问题是,如果在应用程序的新版本中重命名或删除了设置,则 GetPreviousVersion()无法工作。因此,您需要将该设置保留在 Settings类中,但是需要向其添加一些属性/构件,这样您就不会不经意地在其他地方的代码中使用它,从而使其过时。一个过时的设置示例在 VB.NET 中看起来是这样的(可以很容易地转换为 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

确保将此属性添加到具有应用程序设置的同一命名空间/类中。在 VB.NET 中,这个类名为 MySettings,在 My命名空间中可用。可以使用部分类功能来防止过时设置与当前设置混淆。

完全归功于 jsharrison 发布了关于这个问题的 好文章。您可以在那里阅读有关它的更多细节。

这里给出的解决方案有一个变体,它将升级逻辑封装到一个抽象类中,设置类可以从这个抽象类派生。

某些建议的解决方案使用 DefaultSettingsValue 属性指定一个值,该值指示何时未加载以前的设置。我的偏好是简单地使用其默认值指示此类型的类型。作为奖励,日期时间?是有用的调试信息。

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

源自 UserSettingsBase:

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


public MySettings() : base() { }
}

使用它:

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

当我们每个版本只需要升级一次时,下一个简短的解决方案对我很有用。它确实需要像 UpgradeRequired这样的额外设置:

if (!ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).HasFile)
Settings.Default.Upgrade();