不支持关键字:尝试打开 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",它们通常涉及允许您提供新密码的短期令牌。
密码散列和访问恢复过程等主题都有很好的文档记录,因此我不再赘述。
我是 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",它们通常涉及允许您提供新密码的短期令牌。
密码散列和访问恢复过程等主题都有很好的文档记录,因此我不再赘述。