【问题标题】:Storing Application Settings in Project Folder rather than AppData将应用程序设置存储在项目文件夹而不是 AppData
【发布时间】:2012-02-21 09:32:32
【问题描述】:

我的项目中有一个 Settings.cs 文件,我通过

从我的程序中访问其中的数据
Properties.Settings.Default.MyProperty

生成的设置文件存放在以下位置

C:\Users\Foo\AppData\Local\MyApp\MyApp.exe_Url_jknwq2raeohczydfp1loj02nf05zldfk\1.0.0.0\user.config

问题在于,这不仅是特定于用户的,而且还会导致程序为每个签名(调试/发布等)拥有许多 user.config 文件,这会迫使开发人员用户填充整个设置每次他启动还没有特定 user.config 的程序“版本”时。 (如果我不够清楚,我很乐意提供更多细节)

我希望我的应用程序为所有用户提供一个设置文件,无论“版本”如何(调试/发布或其他)。这样,开发用户将不得不设置一次设置,并且这些设置将在每次启动应用程序时生效,而无需为其他签名/用户重新输入它们。

【问题讨论】:

    标签: c# visual-studio-2010


    【解决方案1】:

    您可以像Registry中的所有高级程序一样保存和读取设置,操作方法如下:

    public object GetRegistryValue(string KeyName, object DefaultValue)
            {
                object res = null;
                try
                {
                    Microsoft.VisualBasic.Devices.Computer c = new Microsoft.VisualBasic.Devices.Computer();
                    Microsoft.Win32.RegistryKey k = c.Registry.CurrentUser.OpenSubKey("Software\\YourAppName", true);
                    if (k != null)
                    {
                        res = k.GetValue(KeyName, DefaultValue);
                    }
                    else
                    {
                        k = c.Registry.CurrentUser.CreateSubKey("Software\\YourAppName");
                    }
                    if (k != null)
                        k.Close();
                    // ex As Exception
                }
                catch
                {
                    //PromptMsg(ex)
                }
                return res;
            }
    
    public void SetRegistryValue(string KeyName, object _Value)
            {
                try
                {
                    Microsoft.VisualBasic.Devices.Computer c = new Microsoft.VisualBasic.Devices.Computer();
    
                    Microsoft.Win32.RegistryKey k = c.Registry.CurrentUser.OpenSubKey("Software\\YourAppName", true);
                    if (k != null)
                    {
                        k.SetValue(KeyName, _Value);
                    }
                    else
                    {
                        k = c.Registry.CurrentUser.CreateSubKey("Software\\YourAppName");
                        k.SetValue(KeyName, _Value);
                    }
                    if (k != null)
                        k.Close();
                    // ex As Exception
                }
                catch
                {
                    //PromptMsg(ex)
                }
            }
    

    另一个选择是创建一个包含所有设置作为属性的可序列化类([Serializable()] 属性),然后将其保存在您的应用中目录,带有 BinaryFormatter 类。

    public void saveBinary(object c, string filepath)
    {
        try
        {
            using (System.IO.Stream sr = System.IO.File.Open(filepath, System.IO.FileMode.Create))
            {
                System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                bf.Serialize(sr, c);
                sr.Close();
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
    
    public object loadBinary(string path)
    {
        try
        {
            if (System.IO.File.Exists(path))
            {
                using (System.IO.Stream sr = System.IO.File.Open(path, System.IO.FileMode.Open))
                {
                    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                    object c = bf.Deserialize(sr);
                    sr.Close();
                    return c;
                }
            }
            else
            {
                throw new Exception("File not found");
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        return null;
    }
    

    【讨论】:

    • 谢谢,这当然是一个有趣的选择,但在这种特殊情况下,这正是我想要避免的。我是众多异端中的一员,他们认为注册表是一个非常糟糕的主意,我认为它甚至不应该存在 :-D 我希望我的应用程序尽可能便携,并且系统占用空间最小。序列化不是一个坏主意,如果你有任何代码可以提供......我敢肯定有人在我之前做过这个我宁愿不重新编码 Wheel :-)
    • @Mika,是的,我是你这种异端
    • 感谢 4 更新,感谢您的努力。我真的认为会有一个更简单的选项来保存 VS 的“默认”设置模式并使用范围将配置输出重新路由到所需的单个位置。如果这表明不是一个选项,我可能会选择你的道具作为解决方案/答案。
    【解决方案2】:

    我设计了一个有一些缺点的简单解决方案:

    public void WriteLocalValue(string localKey, string curValue)
    {
        Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
        KeyValueConfigurationElement k = config.AppSettings.Settings[localKey];
        if (k == null)
            config.AppSettings.Settings.Add(localKey, curValue);
        else
            k.Value = curValue;
        config.Save();
    }
    
    public string ReadLocalValue(string localKey, string defValue)
    {
        string v = defValue;
        try
        {
            Configuration config = ConfigurationManager.OpenExeConfiguration( Application.ExecutablePath);
            KeyValueConfigurationElement k = config.AppSettings.Settings[localKey];
            if (k != null) v = (k.Value == null ? defValue : k.Value);
                return v;
        }
        catch { return defValue; }
    }
    

    问题:您需要 UAC assense 来覆盖您的可执行配置,并且您不能使用 Properties.Settings.Default.MyProperty 语法。

    【讨论】:

    • 嗯...有趣的选项。但是,我并没有真正理解 UAC 的缺点。
    • 此代码会覆盖您的配置文件。如果您将应用程序部署在“C:\program files”中,则您没有写入权限。
    【解决方案3】:

    我最终选择了一个更简单直接的替代方案,包括创建一个普通的 Settings 类并按照here 的描述对其进行序列化/反序列化

    【讨论】:

      猜你喜欢
      • 2011-03-19
      • 1970-01-01
      • 2018-07-28
      • 1970-01-01
      • 2012-02-19
      • 1970-01-01
      • 1970-01-01
      • 2017-09-07
      • 2010-09-22
      相关资源
      最近更新 更多