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

发布于 2024-07-13 15:14:26 字数 210 浏览 5 评论 0原文

基本上问题是每次程序集版本更改(即用户安装应用程序的新版本)时,所有设置都会重置为默认值(或更准确地说,在具有不同版本的文件夹中创建新的 user.config 文件数字作为名称)

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

当我们使用 Clickonce 时,它​​似乎能够处理这个问题,所以看起来应该能够完成,但我不确定如何完成。

Basically the problem is that each time the assembly version changes (i.e. the user installs a new version of the application) all their settings are reset the the defaults (or more accurately a new user.config file is created in a folder with a different version number as the name)

How can I keep the same settings when upgrading versions, since using ini files or the registry seem to be discouraged?

When we used Clickonce it seemed to be able to handle this, so it seems like it should be able to be done, but I'm not sure how.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

星光不落少年眉 2024-07-20 15:14:27

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

I know it's been awhile...
In a winforms app, just call My.Settings.Upgrade() before you load them. This will get the latest settings, whether the current version or a previous version.

浮生未歇 2024-07-20 15:14:27

这是我的研究,以防其他人在迁移已更改/删除的设置时遇到困难。 基本问题是,如果您在新版本的应用程序中重命名或删除了该设置,则 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 发布的优秀文章关于这个问题。 您可以在那里阅读有关它的更多详细信息。

Here's my research in case anyone else is having a hard time with migrating settings that have been changed/removed. Basic problem is that GetPreviousVersion() does not work if you have renamed or removed the setting in the new version of your application. So you need to keep the setting in your Settings class, but add a few attributes/artifacts to it so that you don't inadvertently use it in the code elsewhere, making it obsolete. A sample obsolete setting would look like this in VB.NET (can easily be translated to 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

Make sure you add this property to the same namespace/class that has your application settings. In VB.NET, this class is named MySettings and is available in My namespace. You can use partial class functionality to prevent your obsolete settings from mixing up with your current settings.

Full credit to jsharrison for posting an excellent article about this issue. You can read more details about it there.

芸娘子的小脾气 2024-07-20 15:14:27

这是此处提供的解决方案的变体,它将升级逻辑封装到一个抽象类中,设置类可以从中派生。

一些建议的解决方案使用 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();

Here's a variation on the solutions presented here that encapsulates the upgrade logic into an abstract class that settings classes can derive from.

Some proposed solutions use a DefaultSettingsValue attribute to specify a value that indicates when previous settings were not loaded. My preference is to simply use a type whose default value indicates this. As a bonus, a DateTime? is helpful debugging information.

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

Derive from UserSettingsBase:

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

    public MySettings() : base() { }
}

And use it:

// Existing settings are loaded and upgraded if needed
MySettings settings = new MySettings();
...
settings.SomeSetting = "SomeValue";
...
settings.Save();
青瓷清茶倾城歌 2024-07-20 15:14:27

如果您对 user.settings 的更改是以编程方式完成的,那么如何在单独的文件(例如 user.customized.settings)中维护(仅)对 user.settings 的修改的副本?

您可能仍然想在 user.settings 中维护和加载修改后的设置。 但是,通过这种方式,当您使用较新版本的 user.settings 安装应用程序的较新版本时,您可以通过将修改后的设置复制回新的 user.settings 来询问用户是否要继续使用修改后的设置。 您可以批量导入它们,或者更进一步并要求用户确认他们想要继续使用哪些设置。

编辑:我读得太快了关于程序集版本的“更准确”部分,导致新的 user.settings 安装到新的版本特定目录中。 因此,上面的想法可能对您没有帮助,但可能会提供一些思考。

If your changes to user.settings are done programmatically, how about maintaining a copy of (just) the modifications to user.settings in a separate file, e.g. user.customized.settings?

You probably still want to maintain and load the modified settings in user.settings as well. But this way when you install a newer version of your application with its newer version of user.settings you can ask the user if they want to continue to use their modified settings by copying them back into the new user.settings. You could import them wholesale, or get fancier and ask the user to confirm which settings they want to continue to use.

EDIT: I read too quickly over the "more accurately" part about assembly versions causing a new user.settings to be installed into a new version-specific directory. Thus, the idea above probably doesn't help you, but may provide some food for thought.

终难遇 2024-07-20 15:14:27

这就是我处理它的方式:

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

This is how I handled it:

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;

}

and in the settings class, I defined the IsDefault property:

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

In the SaveSettings, I set IsDefault to 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();
}
谁与争疯 2024-07-20 15:14:26

ApplicationSettingsBase 有一个名为 Upgrade 的方法,它可以迁移所有内容以前版本的设置。

为了在发布应用程序的新版本时运行合并,您可以在设置文件中定义一个默认为 true 的布尔标志。 将其命名为 UpgradeRequired 或类似名称。

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

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

有关升级方法的更多信息,请访问 MSDNGetPreviousVersion 也可能值得一看,如果您需要进行一些自定义合并。

ApplicationSettingsBase has a method called Upgrade which migrates all settings from the previous version.

In order to run the merge whenever you publish a new version of your application you can define a boolean flag in your settings file that defaults to true. Name it UpgradeRequired or something similar.

Then, at application start you check to see if the flag is set and if it is, call the Upgrade method, set the flag to false and save your configuration.

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

Read more about the Upgrade method at MSDN. The GetPreviousVersion might also be worth a look if you need to do some custom merging.

﹉夏雨初晴づ 2024-07-20 15:14:26

当我们每个版本只需要升级一次时,下一个简短的解决方案对我有用。 它不需要额外的设置,例如UpgradeRequired

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

The next short solution works for me when we need to upgrade only once per version. It does not required additional settings like UpgradeRequired:

if (!ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).HasFile)
    Settings.Default.Upgrade();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文