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
}
}
}
Related
I'm trying to get the UserName and put it in TempData but I get an error when the code reaches the ExecuteReader() method.
Here's my query code:
var InvoiceId = TempData["newinvoice"];
TempData["invoiceid"] = InvoiceId;
var UserID = TempData["UserID"];
string connection = "Data Source=.;Initial Catalog=project;Integrated Security=true;";
using (SqlConnection sqlconn = new SqlConnection(connection))
{
using (SqlCommand sqlcomm = new SqlCommand("SELECT UserName FROM AspNetUsers WHERE Id = #id"))
{
sqlcomm.Parameters.Add("#id", SqlDbType.VarChar).Value = UserID;
using (SqlDataAdapter sda = new SqlDataAdapter())
{
sqlcomm.Connection = sqlconn;
sqlconn.Open();
sda.SelectCommand = sqlcomm;
SqlDataReader sdr = sqlcomm.ExecuteReader();
while (sdr.Read())
{
TempData["UserId"] = sdr["UserName"];
}
}
}
}
The User Id from TempData["UserID"] is an nvarchar(450) not an integer. I have no clue why that exception is happening - any help?
Note: here's an example from one of my user ids:
'aa776084-053e-452c-8b0d-b445cdbf457d'
It looks like your id is a uniqueidentifier and if so I would recommend changing your database and code to use GUIDs.
However to fix your problem, you should be able to pass in the UserId and call toString() (as the value is most likely an object) e.g:
sqlcomm.Parameters.Add("#id", SqlDbType.NVarChar, UserID.ToString());
If you're only going to return one results, maybe use ExecuteScalar()
using (SqlConnection sqlconn = new SqlConnection(connection))
{
using (SqlCommand sqlcomm = new SqlCommand("SELECT TOP 1 UserName from AspNetUsers where Id=#id", sqlconn)
{
sqlcomm.Parameters.Add("#id", SqlDbType.NVarChar, UserID.ToString());
object result = sqlcomm.ExecuteScalar();
if (result != null)
{
TempData["UserId"] = result.ToString(); // It looks like you're mixing UserId & UserName .
}
}
}
I am trying to create a parameter for all those values that is mentioned below in the code itself.
Any help would be appreciated!
This is what I did:
public static void Main()
{
{
string testEnv = ClaimQuery.ClaimQueryhelper.getTestEnv();
// calls claimQueryhelper for the test environment
var connectionString = ClaimQuery.ClaimQueryhelper.getConnection(testEnv);
// if we are not calling helper then the environment is hard coded
//string connectionString = ConfigurationManager.ConnectionStrings["aitf"].ConnectionString;
//ConsoleWindows.Properties.Settings.Default.ConnectionString;
using (SqlConnection con = connectionString)
{
///Sql to get the data from the Dbase
string sql = "SELECT TOP 3 claim.CLCL_MICRO_ID,cdml.LOBD_ID,cdml.IDCD_ID,CLMD_TYPE, " +
"* FROM CMC_CLCL_CLAIM claim INNER JOIN CMC_CDML_CL_LINE cdml ON claim.CLCL_ID = cdml.CLCL_ID" +
" INNER JOIN CMC_CLMD_DIAG clmd ON claim.CLCL_ID = clmd.CLCL_ID WHERE CLCL_CUR_STS =#CLCL_CUR_STS AND #CLCL_CL_SUB_TYPE AND #CLCL_RECD_DT and #CLMD_TYPE ";
//connecting to the Sql server
using (SqlCommand command = new SqlCommand(sql, con))
//Reading the Sql database
using (SqlDataReader reader = command.ExecuteReader())
{
command.Parameters.Add(
new[]
{
new SqlParameter(#"CLCL_CUR_STS", SqlDbType.Int).Value = "01",
new SqlParameter(#"CLCL_CL_SUB_TYPE", SqlDbType.VarChar).Value = "M",
new SqlParameter(#"CLMD_TYPE", SqlDbType.VarChar).Value = "01",
new SqlParameter(#"CLCL_RECD_DT", SqlDbType.DateTime).Value = "2017-02-03 00:00:00.000",
});
The parameter values for SqlCommand query string (i.e. array of SqlParameter) must be iterated & assigned to the command before DataReader opens by using ExecuteReader. See this example below:
using (SqlConnection con = new SqlConnection(connectionString))
{
// SQL query to get the data from the database
string sql = #"[query string here]";
con.Open();
// connecting to the SQL Server
using (SqlCommand command = new SqlCommand(sql, con))
{
SqlParameter[] parameters = new[]
{
new SqlParameter(#"CLCL_CUR_STS", SqlDbType.Int).Value = "01",
new SqlParameter(#"CLCL_CL_SUB_TYPE", SqlDbType.VarChar).Value = "M",
new SqlParameter(#"CLMD_TYPE", SqlDbType.VarChar).Value = "01",
new SqlParameter(#"CLCL_RECD_DT", SqlDbType.DateTime).Value = "2017-02-03 00:00:00.000",
};
foreach (SqlParameter sqlParam in parameters)
{
command.Parameters.Add(sqlParam);
}
// Reading the SQL database
using (SqlDataReader reader = command.ExecuteReader())
{
// fetch retrieved data
}
}
// other stuff
con.Close();
}
Must declare the scalar variable error obviously means that one or more of provided query parameters are not declared during query statement execution (they're wrongly declared after the DataReader has already open).
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();
//...
This is my Stored Procedure.
DECLARE #listStr VARCHAR(500)
select #listStr = COALESCE(#listStr + ';' ,'') + eml_ID from EmailGroup where eml_Level=3 and eml_Stat=1
SELECT #listStr
I dont have problem when I call this SP on my code behind. What I want to do is to put this SP on my code behind. This is what i tried in my code behind.
using (SqlConnection sqlConn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString))
{
string stR = #"select #listStr = COALESCE(#listStr + ';' ,'') + eml_ID from EmailGroup where eml_Level=3 and eml_Stat=1";
using (SqlCommand cmD = new SqlCommand(stR, sqlConn))
{
sqlConn.Open();
SqlDataReader dR = cmD.ExecuteReader();
cmD.Parameters.Add("#listStr", SqlDbType.VarChar);
while (dR.Read())
{
string emailFullName = Session["UserFullName"].ToString();
string email = Session["UserEmailAdd"].ToString();
//more code here
}
When I tries this approach. I receive error "Must declare the scalar variable "#listStr".
My Question is how can i declare a variable in code behind?
You omited in code behind the variable declaration.
DECLARE #listStr VARCHAR(500);
Your code should be:
using (SqlConnection sqlConn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString))
{
string stR = #"DECLARE #listStr VARCHAR(500); select #listStr = COALESCE(#listStr + ';' ,'') + eml_ID from EmailGroup where eml_Level=3 and eml_Stat=1";
using (SqlCommand cmD = new SqlCommand(stR, sqlConn))
{
// Omitted
Beware to separate your statements with a semicolon ;
select #listStr = COALESCE(....
That should populate a variable, but will not return a result set that you can read with
while (dR.Read()) {}
You should remove the variable assignment if you are executing a query for results...
select COALESCE(....
Are you saying Stored Procedure when you mean Query? A Stored Procedure is a named "function" that expects parameters and returns data. A Stored Procedure contains one or more queries like what you wrote above.
You need to declare the value of listStr, try this:
cmD.Parameters.Add("#listStr", SqlDbType.VarChar, 15, "test");
or
cmD.Parameters.Add("#listStr", SqlDbType.VarChar).Value = "test";
And the compiler is looking for #listStr in your SELECT statement, which is not declared. You need to change your query with something like this:
using (SqlConnection sqlConn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString))
{
using (SqlCommand cmD = new SqlCommand("StoredProcName", sqlConn) { CommandType = CommandType.StoredProcedure })
{
sqlConn.Open();
SqlDataReader dR = cmD.ExecuteReader();
cmD.Parameters.Add("#listStr", SqlDbType.VarChar).Value = "test";
while (dR.Read())
{
string emailFullName = Session["UserFullName"].ToString();
string email = Session["UserEmailAdd"].ToString();
//more code here
}
}
}
You mention a stored procedure, and I strongly recommend you to leverage on separating db implementation from DAL implementation.
So first create the stored procedure in the proper DB:
USE myActualDb /* use the actual db name */
GO
CREATE PROCEDURE GetEmailList
#eml_level int, /* use the actual datatype */
#eml_stat int, /* use the actual datatype */
AS
BEGIN
DECLARE #listStr VARCHAR(500)
SELECT #listStr = COALESCE(#listStr + ';' ,'') + eml_ID
FROM EmailGroup
WHERE eml_Level = #eml_level AND eml_Stat = #eml_stat
SELECT #listStr
END
Then call the stored from the codebehind using ADO.NET SqlClient:
var emlLevel = levelValue;
var emlStat = statValue;
using (SqlConnection sqlConn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = sqlConn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "GetEmailList";
cmd.Parameters.Add(new SqlParameter("eml_level", emlLevel));
cmd.Parameters.Add(new SqlParameter("eml_level", emlStat));
sqlConn.Open();
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
/* do whatever you need with the dr result */
}
/* clean up*/
}
}
I have this sql connection with concatenated strings query and I would like to change it to parameters. I am starting coding on my own and I do not have many reference. Tried googling around but I have not found something clear enough to me.
public bool DBAuthenticate(string strUsername, string strPassword)
{
string sqlstring;
sqlstring = "SELECT * FROM credentials WHERE [Username]='" + strUsername + "' AND [Password]='" + strPassword + "'";
string getconnstring = ConfigurationManager.ConnectionStrings["WTAConnectionString"].ConnectionString;
SqlConnection conn = new SqlConnection(getconnstring);
System.Data.SqlClient.SqlCommand comm = new System.Data.SqlClient.SqlCommand(sqlstring,conn);
System.Data.SqlClient.SqlDataReader reader;
conn.Open();
reader = comm.ExecuteReader();
if (reader.Read())
return true;
else
return false;
}
can someone please show me how to modify the code to change the query from concatenation to parameters? Thank you a lot.
In order to use parameters, you need to change your statement as follows:
SELECT * FROM credentials WHERE [Username]=#username AND [Password]=#password
It then contains two parameters (#username and #password) that you need to provide the values for in the command. You can do this with the AddWithValue method:
// ...
System.Data.SqlClient.SqlCommand comm = new System.Data.SqlClient.SqlCommand(sqlstring,conn);
comm.Parameters.AddWithValue("#username", strUsername);
comm.Parameters.AddWithValue("#password", password);
System.Data.SqlClient.SqlDataReader reader;
// ...
Please also note that you should always dispose the connection, commands and readers reliably, so adding some using blocks will help:
using(SqlConnection conn = new SqlConnection(getconnstring))
{
conn.Open();
using(SqlCommand comm = new System.Data.SqlClient.SqlCommand(sqlstring,conn))
{
// ...
using(SqlDataReader reader = comm.ExecuteReader())
{
// ...
}
}
}
Try this one:
sqlstring = "SELECT * FROM credentials WHERE [Username]=#UserName AND [Password]=#Password";
After the declaration of comm object, write this:
comm.Parameters.Add(new SqlParameter(#UserName,strUsername));
comm.Parameters.Add(new SqlParamter(#Password,strPassword);