【问题标题】:Why are my user-settings not persisted after calling Properties.Settings.Default.Saved()?为什么调用 Properties.Settings.Default.Saved() 后我的用户设置没有保留?
【发布时间】:2019-10-15 06:10:18
【问题描述】:

这仅用于演示目的。我实际上不会以这种方式缓存密码,因为我收到了应用程序设置不安全的建议。

问题陈述

我正在创建一个登录 Windows 窗体应用程序,该应用程序使用 Application Settings 在应用程序会话之间保留输入到 NamePassword 字段中的字符串值。表单应加载从上一个会话输入的 NamePassword 值。

如果我使用 Properties.Settings.Default.Save() 从私有方法保存这些字段值,我遇到了字段无法保存和重新加载的问题:

    // Save the current values of each field
    private void SaveSettings()
    {
        Properties.Settings.Default.Name = textBox1.Text;
        Properties.Settings.Default.Password = textBox2.Text;
        Properties.Settings.Default.Save();
    }

当字段值改变时,`SaveSettings() 将被调用:

    // Saves ALL field values in the form whenever the field changes. 
    // Warning: This function gets called each time a character is added to the 'Name' field.
    private void textBox1_TextChanged(object sender, EventArgs e)
    {
        SaveSettings();
        UpdateRichTextbox();
    }

    // Saves ALL field values in the form whenever the field changes. 
    // Warning: This function gets called each time a character is added to the 'Password' field.
    private void textBox2_TextChanged(object sender, EventArgs e)
    {
        SaveSettings();
        UpdateRichTextbox();
    }

UpdateRichTextbox() 只是以格式化的方式将NamePassword 写入富文本框,以便我可以看到它们的值:

    // Writes current values of each setting to Rich Textbox
    private void UpdateRichTextbox()
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine($"Name: {Properties.Settings.Default.Name}");
        sb.AppendLine($"Password: {Properties.Settings.Default.Password}");
        richTextBox1.Text = sb.ToString();
    }

尝试

我确保将项目设置中的 NamePassword 设置为 set the scope 为“用户”。我在 .Save() 之后尝试了 calling Properties.Settings.Default.Upgrade()

当我将SaveSettings() 的内容移动到更改这些字段时调用的回调时,NamePassword 仍然存在:

    // Saves ALL field values in the form whenever the field changes. 
    // Warning: This function gets called each time a character is added to the 'Name' field.
    private void textBox1_TextChanged(object sender, EventArgs e)
    {
        Properties.Settings.Default.Name = textBox1.Text;
        Properties.Settings.Default.Save();
        UpdateRichTextbox();
    }

    // Saves ALL field values in the form whenever the field changes. 
    // Warning: This function gets called each time a character is added to the 'Password' field.
    private void textBox2_TextChanged(object sender, EventArgs e)
    {
        Properties.Settings.Default.Password = textBox2.Text;
        Properties.Settings.Default.Save();
        UpdateRichTextbox();
    }

我不确定为什么我的第一种方法不起作用。 API 开发人员打算如何使用 .Save()

完整示例

using System;
using System.Text;
using System.Windows.Forms;

namespace LoginForm
{
    public partial class Form1 : Form
    {
        // Called initially when the form application starts up
        public Form1()
        {
            InitializeComponent();
            LoadSettings();
        }

        // Load saved values to their respective field textboxes
        private void LoadSettings()
        {
            textBox1.Text = Properties.Settings.Default.Name;
            textBox2.Text = Properties.Settings.Default.Password;
        }

        // Writes current values of each setting to Rich Textbox
        private void UpdateRichTextbox()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine($"Name: {Properties.Settings.Default.Name}");
            sb.AppendLine($"Password: {Properties.Settings.Default.Password}");
            richTextBox1.Text = sb.ToString();
        }

        // Saves ALL field values in the form whenever the field changes. 
        // Warning: This function gets called each time a character is added to the 'Name' field.
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            Properties.Settings.Default.Name = textBox1.Text;
            Properties.Settings.Default.Save();
            UpdateRichTextbox();
        }

        // Saves ALL field values in the form whenever the field changes. 
        // Warning: This function gets called each time a character is added to the 'Password' field.
        private void textBox2_TextChanged(object sender, EventArgs e)
        {
            Properties.Settings.Default.Password = textBox2.Text;
            Properties.Settings.Default.Save();
            UpdateRichTextbox();
        }
    }
}

【问题讨论】:

  • 如果您更改了应用程序的版本,请查看[Drive:]\Users\[CurrentUser]\AppData\Local\[YouAppName]\URL\[Version] 有多少user.config 文件。
  • 我不知道如何更改我的应用程序的版本。我检查了那个目录,但是我的应用程序没有对应的目录(它的名字是LoginForm)。此应用程序存在的唯一配置文件位于 LoginForm\bin\debug(VS 项目文件夹,调试构建输出)中,名为 LoginForm.exe.config
  • [Application].exe.configapp.config反映。默认值存储在那里。可以在运行时更改的用户值存储在user.config 文件中。删除这 2 个设置。重建解决方案(不是项目)。添加回这两个设置,而不在值字段中写入任何内容。重建解决方案。现在在应用程序运行时保存新的设置值。去AppData/Local检查user.config文件是否已经创建。
  • 我在C:\Users\[CurrentUser]\AppData\Local\Microsoft\LoginForm.exe_Url_* 中找到了 3 个user.config 文件。有 3 个名为 LoginForm.exe_Url_* 的目录(* 表示一串字母数字)。每次我修改设置条目并重建解决方案时,似乎都会创建一个带有另一个 user.config 文件的新目录。设置以纯文本形式存储 - 哎呀,根本不是存储密码的好方法!
  • 很好,您发现了递归调用 :) TextChanged 事件可能不是调用 SaveSettings 方法的正确 位置 (它很少是任何事情的正确事件:)。密码可以存储为文本。好吧,密码的加盐哈希转换为 base64 字符串。

标签: c# winforms settings


【解决方案1】:

当应用程序重新启动时,Form1() 调用 LoadSettings(),它在执行 textBox1.Text = Properties.Settings.Default.Name 时会修改 textBox1.Text 属性,从而导致 textBox1_TextChanged 处理程序运行。该处理函数调用SaveSettings(),然后使用textBox2.Text 字段中当前存储的内容覆盖之前存储在Properties.Settings.Default.Password 中的内容。由于应用程序已重新启动,textBox2.Text 为空,因此 Properties.Settings.Default.Password 的旧值被空字符串覆盖。

感谢Jimi 帮助我找到user.config 文件,并感谢他对textChanged 事件中不该做什么的明智建议。我看不出为什么每次textBox 中的字符发生变化时你都需要做某事的充分理由——为什么大多数应用程序使用ApplySave 按钮是有道理的。在我逐步调试时看到此文件更改帮助我确定了我的代码的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-27
    • 1970-01-01
    • 2020-07-23
    • 1970-01-01
    • 1970-01-01
    • 2013-05-22
    • 2018-08-23
    • 2020-07-16
    相关资源
    最近更新 更多