【问题标题】:How do you keep user.config settings across different assembly versions in .net?您如何在 .net 中跨不同程序集版本保留 user.config 设置?
【发布时间】:2010-10-06 18:18:59
【问题描述】:

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

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

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

【问题讨论】:

  • 不,这是指默认不将文件签入版本控制(或者我收集到的)这是关于最终用户的(Windows)用户特定设置
  • 正是我需要的问题,谢谢:)
  • 我已经在以下线程中发布了一个可能的解决方案:stackoverflow.com/a/47921377/3223783希望对您有所帮助!
  • 我在this thread 中发布了一个可能的解决方案。希望有帮助!

标签: .net settings assemblyversions


【解决方案1】:

ApplicationSettingsBase 有一个method called Upgrade,它会迁移以前版本的所有设置。

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

然后,在应用程序启动时检查标志是否已设置,如果已设置,请调用 Upgrade method,将标志设置为 false 并保存配置。

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

MSDN 上阅读有关升级方法的更多信息。如果您需要进行一些自定义合并,GetPreviousVersion 可能也值得一看。

【讨论】:

  • 一个小问题,什么是新版本? 4 零件号的任何部分?我使用 ClickOnce,那是另一种动物吗?
  • UpgradeRequired应该是什么类型的设置? appSettingsuserSettings 还是 applicationSettings?作为 Settings.Settings 上的用户设置,一旦第一次更改为 false,它将永远不会再次为 true。新版本不会将 UpgradeRequired 重置为 True。
  • @dialex 它必须是用户设置。 Application 类型的设置是只读的。新版本号确实会导致设置重置,因为设置存储在特定于版本的路径中。
  • 除了UpgradeRequired之外,我会将应用程序的版本存储为设置,而不是/。这允许您执行自定义升级转换(即,将无效值/有效值转换为 - 最新版本的默认值/ - 相同值以外的值)。您可以拥有将需要转换的每个适用版本转换为需要它的下一个最低版本的代码,并将代码菊花链在一起,从而:a)降低最新版本转换代码的复杂性,b)允许潜在的旧转换代码退役。
  • 我想我已经回答了我自己的问题。如果存在以前版本的设置文件,它会在每次应用启动时将其值复制到最新版本中,这可能不是您想要的!
【解决方案2】:

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

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

【讨论】:

  • 谢谢,它在调试期间确实有效。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

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

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

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

        【讨论】:

          【解决方案7】:

          我是这样处理的:

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

          【讨论】:

            猜你喜欢
            • 2017-12-03
            • 2011-01-11
            • 2014-07-18
            • 1970-01-01
            • 1970-01-01
            • 2019-11-08
            • 2010-10-27
            • 1970-01-01
            相关资源
            最近更新 更多