I have an Object Query in MS Access (getUserLogin) that will execute the following:
PARAMETERS prmUsername Text, prmPassword Text;
SELECT ID, LastName, FirstName, MiddleName
FROM tblUsers
WHERE Username = [prmUsername] AND Password = [prmPassword];
I have a method in my C# to execute the Object Query in MS Access (getUserLogin).
public bool login(string username, string password)
{
com = new OdbcCommand("EXEC getUserLogin", con);
com.CommandType = CommandType.StoredProcedure;
com.Parameters.Add("prmUsername", OdbcType.Text).Value = username;
com.Parameters.Add("prmPassword", OdbcType.Text).Value = password;
con.Open();
rea = com.ExecuteReader(); //OdbcException goes here
if (rea.HasRows == true)
return true;
else
return false;
}
I'm getting this OdbcException:
ERROR [07002] [Microsoft][ODBC Microsoft Access Driver] Too few
parameters. Expected 2.
Your first problem is that your query uses parameter names that are the same as the corresponding field names. If you try to run your query in Access it will prompt you for the "Username" and "Password" parameters and then return all rows in tblUsers regardless of the parameter values you enter. That is because when the Access SQL parser processes
... WHERE Username = [Username] AND Password = [Password]
... it interprets [Username] and [Password] as field names, not parameter names, and the result is the same as
... WHERE True AND True
So, the first thing you need to do is change your parameter names. One relatively common convention is to use a "prm" prefix for parameter names, so your query would be
PARAMETERS prmUsername Text, prmPassword Text;
SELECT [ID], [LastName], [FirstName], [MiddleName]
FROM [tblUsers]
WHERE [Username] = [prmUsername] AND [Password] = [prmPassword];
Now, to pass your parameter values in your C# application you need to use System.Data.OleDb (not .Odbc) with code something like this
using (var con = new OleDbConnection(myConnectionString))
{
con.Open();
using (var cmd = new OleDbCommand())
{
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "loginQuery";
cmd.Parameters.Add("prmUsername", OleDbType.VarWChar).Value = "eric";
cmd.Parameters.Add("prmPassword", OleDbType.VarWChar).Value = "abcdefg";
using (OleDbDataReader rdr = cmd.ExecuteReader())
{
if (rdr.Read())
{
Console.WriteLine("Row found: ID = {0}", rdr["ID"]);
}
else
{
Console.WriteLine("Row not found.");
}
}
}
}
Related
The following subroutine should update the text in the database to new user input, however, when I check the database nothing has changed?
private void UpdatePassword(string Username, string NewPassword)
{
string SQLStatement =
"UPDATE [Login Details] SET [PASSWORD] = #password WHERE [USERNAME] = #username";
OleDbConnection connString = new OleDbConnection(#"Provider = Microsoft.ACE.OLEDB.12.0; Data Source = TrigonometryToolDatabase.accdb");
OleDbCommand cmd = new OleDbCommand(SQLStatement, connString);
cmd.Parameters.AddWithValue("#username", Username);
cmd.Parameters.AddWithValue("#password", NewPassword);
connString.Open();
cmd.ExecuteNonQuery();
connString.Close();
}
Parameters in MS Access / OleDB is positional - they are NOT matched on name (like in ADO.NET / SQL Server) - but on their position in the query string.
You have
string SQLStatement =
"UPDATE [Login Details] SET [PASSWORD] = #password WHERE [USERNAME] = #username";
so the first parameter you pass in will need to be the password, the username comes second.
However, in your code, you're doing it just the other way around:
cmd.Parameters.AddWithValue("#username", Username);
cmd.Parameters.AddWithValue("#password", NewPassword);
So flip these two lines, and you should be good:
cmd.Parameters.AddWithValue("#password", NewPassword);
cmd.Parameters.AddWithValue("#username", Username);
Im using Database Data for my Project and when I type a letter in Textbox1, the application crashes with the error:
System.Data.SqlClient.SqlException: "Invalid column name 'e'."
Database name is Table with "Id" and "altitudes"
Id is a varchar and altitudes is a nchar.
Thats how I want it to work:
Typing a Name in name.Text, search for the name in the database and paste the assigned altitude in altitude.Text.
Altitudes are numbers, Names are Letters in the database.
Where's the error in my code? (Data Source is on purpose blank)
{
String source = #"Data Source=";
SqlConnection con = new SqlConnection(source);
con.Open();
String sqlSelectQuery = "SELECT * FROM [Table] WHERE ID ="+char.Parse(name.Text);
SqlCommand cmd = new SqlCommand(sqlSelectQuery, con);
SqlDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{
altitude.Text = (dr["altitudes"].ToString());
}
con.Close();
}
You should never concatenate inputs to create SQL. It is horribly brittle, and susceptible to SQL injection, and i18n/l10n problems (formatting of values). Lots of bad things.
The solution should always be: parameters.
For example:
const string sqlSelectQuery = "SELECT * FROM [Table] WHERE ID = #id";
using SqlCommand cmd = new SqlCommand(sqlSelectQuery, con);
cmd.Parameters.AddWithValue("#id", name.Text);
// Etc
Or more easily with a tool like Dapper:
var alt = con.QuerySingleOrDefault<string>(
"SELECT altitudes FROM [Table] WHERE ID = #id",
new { id = name.Text });
I have a code that should test a login.
When I execute literally, it works, returning one row (that's expected). When I use parameters on sqlcommand, I don't get any row.
It works (literal values for username and password):
string strConn = 'string connection';
SqlConnection conn = new SqlConnection(strConn);
SqlCommand sqlCommand = new SqlCommand();
sqlCommand.Connection = conn;
sqlCommand.Parameters.Clear();
sqlCommand.CommandText = #"select *
from
Usuario
where
Username = 'test' and
Password = CONVERT(VARCHAR(32), ashBytes('MD5', 'test'), 2)";
conn.Open();
SqlDataReader ret = sqlCommand.ExecuteReader();
But it doesn't work (parameters values for username and password):
string strConn = 'string connection';
SqlConnection conn = new SqlConnection(strConn);
SqlCommand sqlCommand = new SqlCommand();
sqlCommand.Connection = conn;
sqlCommand.Parameters.Clear();
sqlCommand.CommandText = #"select *
from
Usuario
where
Username = #login and
Password = CONVERT(VARCHAR(32), ashBytes('MD5', #pass), 2)";
SqlParameter user = new SqlParameter("#login", SqlDbType.NVarChar, 50) { Value = "test" };
SqlParameter pass = new SqlParameter("#pass", SqlDbType.NVarChar, 50) { Value = "test" };
List<SqlParameter> list = new List<SqlParameter>();
list.Add(user);
list.Add(pass);
sqlCommand.Parameters.AddRange(list.ToArray<SqlParameter>());
conn.Open();
SqlDataReader ret = sqlCommand.ExecuteReader();
I don't have an sintax error or something like that. The second code just don't returns rows.
I've tried to use sqlCommand.Parameters.AddWithValue, but I have no success too.
'test' and N'test' are not the same thing when you convert them to a hash. One is ASCII and the other is Unicode. If they are both ASCII then use SqlDbType.VarChar (not SqlDbType.NVarChar) in your parameter.
Difference illustrated in Sql
DECLARE #passUnicode Nvarchar(100) = N'test'
DECLARE #passAscii varchar(100) = 'test'
SELECT CONVERT(VARCHAR(32), HashBytes('MD5', #passAscii), 2) AS [Md5OfAscii]
, CONVERT(VARCHAR(32), HashBytes('MD5', #passUnicode), 2) AS [Md5OfUnicode]
Results
098F6BCD4621D373CADE4E832627B4F6, C8059E2EC7419F590E79D7F1B774BFE6
Side notes
Password Hashing
I recommend against storing passwords as MD5, MD5 is simply not secure. There are plenty of alternatives out there like pbkdf2, bcrypt, and scrypt to name a few of the more generally accepted secure password hashing algorithms.
c# structure
When working with Ado.net (or with any resources for that matter) you should wrap your Connections, DataReaders, Adapters, etc that implement IDisposable in using blocks. This will ensure external resources are always freed, even in the event of a connection.
string connectionString = "";
using (var connection = new SqlConnection(connectionString))
{
using (var command = new SqlCommand
{
CommandText = #"select * from Usuario where Username = #login and Password = CONVERT(VARCHAR(32), HASHBYTES('MD5', #pass), 2)",
CommandType = CommandType.Text,
Connection = connection
})
{
command.Parameters.Add(new SqlParameter("login", SqlDbType.VarChar, 50) { Value = "test" });
command.Parameters.Add(new SqlParameter("pass", SqlDbType.VarChar, 50) { Value = "test" });
connection.Open();
using (var dataReader = command.ExecuteReader())
{
// do some stuff
}
}
}
I am trying to login using LoginID and Password as user name and password respectively, however I'm getting an exception:
Must declare the scalar variable “#loginName”
protected void SignInButton_Click(object sender, EventArgs e)
{
int customerId = 0;
int loginName = Convert.ToInt32(LoginTextBox.Text);
string password = PasswordTextBox.Text;
SqlCommand command = new SqlCommand();
SqlDataReader reader;
command.CommandText = "Select CustomerID from Customers where LoginID= #loginName and Password= #password";
command.Parameters.AddWithValue("#LoginID", loginName);
command.Parameters.AddWithValue("#Password", password);
command.Parameters.AddWithValue("#CustomerID", customerId);
reader = DbUtility.GetDataReader(command);
if (reader.HasRows)
{
reader.Read();
customerId = reader.GetInt32(0);
Session["CustomerID"] = customerId;
Response.Redirect("ListCategories.aspx");
}
else
{
MessegeLabel.Text = "User Name or Password Incorrect";
}
}
You have some SQL there which includes the parameter #loginName. You never provide that parameter; you provide an unused parameter called #LoginID instead (along with an unused #CustomerID also, for some reason).
It's telling you that it needs you to provide all the parameters your SQL snippet uses.
command.CommandText = "Select CustomerID from Customers where LoginID= #loginName and Password= #password";
command.Parameters.AddWithValue("#LoginID", loginName);
command.Parameters.AddWithValue("#Password", password);
command.Parameters.AddWithValue("#CustomerID", customerId);
So provide it:
command.Parameters.AddWithValue("#loginName", loginName);
I am trying to get a simple SQLite database working. I'm using the official SQLite extension for C# and I'm using DataGrip from IntelliJ to verify the data is there, yet my C# program doesn't get any results.
This is the code that executes the query:
SQLiteConnection connection = new SQLiteConnection(DbDsn);
User user = new User();
using (connection)
{
connection.Open();
string sql = "SELECT * FROM user WHERE username = #username ;";
SQLiteCommand command = new SQLiteCommand(sql, connection);
command.Prepare();
command.Parameters.AddWithValue("#username", username);
SQLiteDataReader reader = command.ExecuteReader();
if (reader.Read())
{
user.Id = (int) reader["id"];
user.Username = reader["username"] as string;
user.Password = reader["password"] as string;
user.Name = reader["name"] as string;
user.LastName = reader["last_name"] as string;
user.Type = (UserTypes) reader["type"];
}
else
{
throw new ObjectNotFoundException();
}
connection.Close();
}
And this is the result of a simple Select * From user; query on the user table (done on DataGrip):
id username passw… name last_name type
1 managertest oAWpW… BENJAMIN ARIEL NAVA MARTINEZ 1
2 clerktest iRYMz… EMPLEADO PRUEBA 0
As you can see, the records are there (an I've verified that the query is being performed on the exact same file), however, the C# program seems to skip the if statement (because read returns false) as if there were no rows in the database, what is the problem here?
Call SQLiteCommand.Prepare AFTER you have completed constructing your command
//...
string sql = "SELECT * FROM user WHERE username = #username ;";
SQLiteCommand command = new SQLiteCommand(sql, connection);
command.Parameters.AddWithValue("#username", username);
// Call Prepare after setting the Commandtext and Parameters.
command.Prepare();
SQLiteDataReader reader = command.ExecuteReader();
//...