我是C#和SQL的新手,所以非常感谢您的帮助和建议。
我的想法是通过SQL连接到DB,选择密码和电子邮件,然后通过e-mail(SMTP连接)将其发送给想要恢复帐户密码的人。 )。
我的问题是,我试图通过SQL为C#项目设置密码恢复选项,但是出现以下错误:[[错误:“不支持的关键字:'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>
这是我的密码恢复类文件:
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("[email protected]"); // 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("[email protected]", "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(); } } }
frmRecoveryPassword
类中硬编码为cs
字段的代码。SqlConnection
抱怨,因为它无法识别至少一个名称/值对。这是因为它是OLEDB的连接字符串,而不是SQL Server。
根据您发布的内容,您似乎正在尝试连接到Access数据库。为此,您需要使用OleDbConnection
。但是,根据评论,事实并非如此。您确实要连接到SQL Server数据库,因此SqlConnection
是正确的,而您的[[连接字符串是错误的。
从您发布的内容开始(而不是此后所做的更改),您唯一需要更改的是此行:
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 Server数据库。屏幕快照中的一个(来自注释)是错误的。它是混合的:您已经指定了
OleDb
提供程序(用于Access)和SQL Server数据库文件。似乎您从app.config中的第一个连接字符串复制了.mdf文件的路径,并在第二个.accdb文件所在的位置使用了该路径。SqlConnection
将为您提供与原始问题相同的例外,因为它无法识别"Provider"
键,而OleDbConnection
将为您提供“无法识别的数据库格式”。任何一种连接类型都是错误的。无论您使用的是SQL Server还是Access数据库-看来您的应用程序都连接到这两个数据库-您需要确保为该数据库使用正确的连接类型和连接字符串。
现在让我们深入探讨其他一些问题:
SQL注入
不要连接字符串以构造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
重载,但我更喜欢此重载,因为它很清楚您正在设置哪些属性与许多其他重载。我见过人们使用错误的“数据库类型”并获得运行时错误,而不是编译错误,例如当他们使用Oracle或MySql时传递一个SqlDbType
值,并且它默默地将该值作为object value
参数传递。您会在SO的许多答案中遇到这些过载的示例。
您还将看到AddWithValue
经常使用-don't use it。至少对于SQL Server而言,这比它值得的麻烦更多。
密码恢复这就是我所说的确切查询的危险...
从不以纯文本格式存储密码。您永远不要向他人发送密码,因为您永远都无法检索它。相反,您的数据库应包含密码的哈希。您的
User_Password
列不仅对人眼而且对于用于检索它的任何系统都应该看起来像垃圾。“密码恢复”是一个不正确的名词,如果您做对的话。处理忘记密码的现代实践实际上是“访问恢复”,并且通常涉及短暂的令牌,这些令牌使您可以提供新密码。
密码哈希和访问恢复过程之类的话题已得到充分记录,因此我不再赘述。