您如何在 .net 中跨不同程序集版本保留 user.config 设置?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/534261/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you keep user.config settings across different assembly versions in .net?
提问by Davy8
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)
基本上问题在于,每次程序集版本更改(即用户安装应用程序的新版本)时,所有设置都将重置为默认值(或者更准确地说,在具有不同版本的文件夹中创建新的 user.config 文件编号作为名称)
How can I keep the same settings when upgrading versions, since using ini files or the registry seem to be discouraged?
升级版本时如何保持相同的设置,因为似乎不鼓励使用 ini 文件或注册表?
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.
当我们使用 Clickonce 时,它似乎能够处理这个问题,所以它似乎应该能够完成,但我不确定如何。
回答by Markus Olsson
ApplicationSettingsBase has a method called Upgradewhich migrates all settings from the previous version.
ApplicationSettingsBase 有一个名为 Upgrade的方法,它迁移以前版本的所有设置。
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 UpgradeRequiredor something similar.
为了在您发布应用程序的新版本时运行合并,您可以在设置文件中定义一个默认为 true 的布尔标志。将其命名为UpgradeRequired或类似名称。
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.
然后,在应用程序启动时,您检查该标志是否已设置,如果已设置,则调用Upgrade 方法,将标志设置为 false 并保存您的配置。
if (Settings.Default.UpgradeRequired)
{
Settings.Default.Upgrade();
Settings.Default.UpgradeRequired = false;
Settings.Default.Save();
}
Read more about the Upgrade method at MSDN. The GetPreviousVersionmight also be worth a look if you need to do some custom merging.
在MSDN 上阅读有关升级方法的更多信息。如果您需要进行一些自定义合并,GetPreviousVersion也可能值得一看。
回答by Davy8
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.
我知道已经有一段时间了......在一个 winforms 应用程序中,只需My.Settings.Upgrade()在加载它们之前调用。这将获得最新的设置,无论是当前版本还是以前的版本。
回答by dotNET
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 Settingsclass, 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#):
这是我的研究,以防其他人在迁移已更改/删除的设置时遇到困难。基本问题是,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
Make sure you add this property to the same namespace/class that has your application settings. In VB.NET, this class is named MySettingsand is available in Mynamespace. You can use partial class functionality to prevent your obsolete settings from mixing up with your current settings.
确保将此属性添加到具有应用程序设置的相同命名空间/类。在 VB.NET 中,此类被命名MySettings并在My命名空间中可用。您可以使用部分类功能来防止过时的设置与当前设置混淆。
Full credit to jsharrison for posting an excellent articleabout this issue. You can read more details about it there.
回答by jeff krueger
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.
一些建议的解决方案使用 DefaultSettingsValue 属性来指定一个值,该值指示未加载先前设置的时间。我的偏好是简单地使用默认值表明这一点的类型。作为奖励,DateTime?是有用的调试信息。
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:
从 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();
回答by JMD
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?
如果您对 user.settings 的更改以编程方式完成,那么如何在单独的文件(例如 user.customized.settings)中维护(仅)对 user.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.
您可能还想在 user.settings 中维护和加载修改后的设置。但是这样,当您使用较新版本的 user.settings 安装较新版本的应用程序时,您可以询问用户是否要通过将修改后的设置复制回新的 user.settings 来继续使用它们。您可以批量导入它们,或者更高级并要求用户确认他们想要继续使用哪些设置。
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.
编辑:我读得太快了关于程序集版本的“更准确”部分,导致新的 user.settings 被安装到新的特定于版本的目录中。因此,上面的想法可能对您没有帮助,但可能会提供一些思考。
回答by Ian
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:
在设置类中,我定义了 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; }
}
In the SaveSettings, I set IsDefault to false:
在 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();
}

