不支持关键字:尝试打开 SQL 连接时 'provider'

Keyword not supported: 'provider' when trying to open SQL connection

我是 C# 和 SQL 的新手,非常感谢您的帮助和建议。

我的想法是使用 SQL 连接,select 密码和电子邮件连接到 DB , 并通过邮件(SMTP连接).

发送给想找回账号密码的人

我的问题是我正在尝试通过 SQL 为我的 C# 项目创建密码恢复选项,但我收到以下 错误:"Keyword not supported: 'provider'".

这是我的 app.config 文件:

    <?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
</configSections>
<connectionStrings>
    <add name="Sales_and_Inventory_System__Gadgets_Shop_.Properties.Settings.POS_DBConnectionString" connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\bin\Debug\POS_DB.mdf;Integrated Security=True;Connect Timeout=30" providerName="System.Data.SqlClient" />
    <add name="Restaurant_Management_System.Properties.Settings.SIS_DBConnectionString" connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\bin\Debug\SIS_DB.accdb" providerName="System.Data.OleDb" />
    <add name="Restaurant_Management_System.Properties.Settings.POS_DBConnectionString" connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\bin\Debug\POS_DB.mdf;Integrated Security=True;Connect Timeout=30" providerName="System.Data.SqlClient" />
    <add name="Restaurant_Management_System.Properties.Settings.RMS_DBConnectionString" connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\bin\Debug\RMS_DB.mdf;Integrated Security=True;Connect Timeout=30" providerName="System.Data.SqlClient" />
</connectionStrings>
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
<system.data>
    <DbProviderFactories>
      <remove invariant="System.Data.SQLite" />
      <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
    </DbProviderFactories>
  </system.data></configuration>

这是我的密码恢复 class 文件:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Net.Mail;
namespace Restaurant_Management_System
{
    public partial class frmRecoveryPassword : MetroFramework.Forms.MetroForm
    {
         String cs = "Provider=Microsoft.ACE.Sql.12.0;Data Source=|DataDirectory|\SIS_DB.accdb;";

        public frmRecoveryPassword()
        {
            InitializeComponent();
        }

        private void RecoveryPassword_Load(object sender, EventArgs e)
        {
            txtEmail.Focus();
        }

        private void RecoveryPassword_FormClosing(object sender, FormClosingEventArgs e)
        {

            this.Hide();
            frmLogin frm = new frmLogin();
            frm.txtUserName.Text = "";
            frm.txtPassword.Text = "";
            frm.txtUserName.Focus();
            frm.Show();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Cursor = Cursors.Default;
           timer1.Enabled = false;
        }

        private void metroTile1_Click(object sender, EventArgs e)
        {
            if (txtEmail.Text == "")
            {
                MessageBox.Show("Enter your email", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                txtEmail.Focus();
                return;
            }
            try
            {
                Cursor = Cursors.WaitCursor;
                timer1.Enabled = true;
                DataSet ds = new DataSet();
                SqlConnection con = new SqlConnection(cs);
                con.Open();
                SqlCommand cmd = new SqlCommand("SELECT User_Password FROM Registration Where Email = '" + txtEmail.Text + "'", con);

                SqlDataAdapter da = new SqlDataAdapter(cmd);
                da.Fill(ds);
                con.Close();
                if (ds.Tables[0].Rows.Count > 0)
                {
                    MailMessage Msg = new MailMessage();
                    // Sender e-mail address.
                    Msg.From = new MailAddress("abcd@gmail.com");
                    // Recipient e-mail address.
                    Msg.To.Add(txtEmail.Text);
                    Msg.Subject = "Your Password Details";
                    Msg.Body = "Your Password: " + Convert.ToString(ds.Tables[0].Rows[0]["user_Password"]) + "";
                    Msg.IsBodyHtml = true;
                    // your remote SMTP server IP.
                    SmtpClient smtp = new SmtpClient();
                    smtp.Host = "smtp.gmail.com";
                    smtp.Port = 587;
                    smtp.Credentials = new System.Net.NetworkCredential("abcd@gmail.com", "abcd");
                    smtp.EnableSsl = true;
                    smtp.Send(Msg);
                    MessageBox.Show(("Password Successfully sent " + ("\r\n" + "Please check your mail")), "Thank you", MessageBoxButtons.OK, MessageBoxIcon.Information); this.Hide();
                    frmLogin LoginForm1 = new frmLogin();
                    LoginForm1.Show();
                    LoginForm1.txtUserName.Text = "";
                    LoginForm1.txtPassword.Text = "";
                    LoginForm1.ProgressBar1.Visible = false;
                    LoginForm1.txtUserName.Focus();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void metroTile2_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}

您的 post 正文中有五 (5!) 个连接字符串。您唯一使用的是 frmRecoveryPassword class 中硬编码为 cs 字段的那个。

SqlConnection 抱怨,因为它至少无法识别 name/value 对中的一对。那是因为它是 OLEDB 的连接字符串,而不是 SQL 服务器。

根据您 post 编辑的内容,您似乎在尝试连接到 Access 数据库。为此,您需要使用 OleDbConnection。但是,根据评论,情况并非如此。您真的想连接到 SQL 服务器数据库,所以 SqlConnection 是正确的,而您的 连接字符串 是错误的。

从您 post 编辑的内容开始(而不是您之后所做的更改),您唯一需要更改的是这一行:

SqlConnection con = new SqlConnection(cs);

改成这样:

// Pick one of the three names in app.config that refers to a SQL Server database.
// I chose the first one for this example.
string connectionStringName = "Sales_and_Inventory_System__Gadgets_Shop_.Properties.Settings.POS_DBConnectionString";

string connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;

SqlConnection con = new SqlConnection(connectionString);

这将通过 connectionStringName 中指定的名称检索连接并将其提供给 SqlConnection

确保您使用正确的连接字符串来完成此点击处理程序的操作。


连接字符串

现在让我们检查连接字符串。

app.config 中的那些似乎是正确的,因为它们为每个指定的 providerName 属性提供了看起来正确的值。第二个指向 Access 数据库,另外三个指向 SQL 服务器数据库。

屏幕截图(来自评论)中的错误。它是一个混合体:您指定了一个 OleDb 提供程序(用于 Access)和一个 SQL 服务器数据库文件。看起来您从 app.config 中的第一个连接字符串复制了 .mdf 文件的路径,并在 .accdb 文件所在的第二个连接字符串中使用了它。 SqlConnection 会给出与原始问题相同的异常,因为它无法识别 "Provider" 键,而 OleDbConnection 会给你 "unrecognized database format"。任何一种连接都是错误的。

无论您使用的是 SQL 服务器数据库还是 Access 数据库——看起来您的应用程序都连接到这两者——您需要确保为该数据库使用正确的连接类型和连接字符串。


现在让我们深入研究其他一些问题:

SQL 注射

Do not concatenate strings to construct SQL.

请务必阅读 Little Bobby Tables。避免 SQL 注入不应该是事后才想到的。从一开始就保护您的应用程序。这样做的方法是参数化您的查询。

暂时忽略这个确切查询的危险,这是你应该做的:

SqlCommand cmd = new SqlCommand("SELECT User_Password FROM Registration WHERE Email = @Email");
                                                                                   // ^^^^^^ parameter
cmd.Parameters.Add(new SqlParameter
{
    Name = "@Email",
    SqlDbType = SqlDbType.NVarChar,
    Size = 100, // or whatever length your Email column is.
    Value = txtEmail.Text
         // ^^^^^^^^^^^^^ paramter's value
});

还有其他 Add 重载可供您使用,但我更喜欢这个重载,因为与许多其他重载相比,您设置的属性非常清楚。我见过人们使用错误的 "DB Type" 并得到运行时错误而不是编译错误,例如当他们使用 Oracle 或 MySql 时传递 SqlDbType 值,它会默默地将该值作为 object value 参数传递。您将在 SO 的许多答案中遇到这些重载的示例。

您还会看到 AddWithValue 经常使用 -- don't use it。麻烦多于它的价值,至少对于 SQL 服务器。

密码恢复

这就是我所说的确切查询的危险...

Never store passwords in plain text.

您不应该将密码发送给其他人,因为您永远无法找回密码。相反,您的数据库应该包含密码的哈希值。您的 User_Password 列应该看起来像垃圾,不仅对于人眼而且对于用于检索它的任何系统也是如此。

"Password recovery" 是一个不准确的术语,当你做对的时候。处理遗忘密码的现代做法确实 "access recovery",它们通常涉及允许您提供新密码的短期令牌。

密码散列和访问恢复过程等主题都有很好的文档记录,因此我不再赘述。