I am trying to create a simple username/password login using SQL and it always shows up as invalid. Can I please get some feedback?
SqlConnection cn;
cn = new SqlConnection();
cn.ConnectionString = "Data source=(local); Initial Catalog=INT422Assignment1; Integrated Security=SSPI;";
cn.Open();
SqlCommand cmd;
cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandText = "SELECT username, pwd FROM myLogin WHERE userNameTB = #username AND passWordTB = #pwd";
SqlParameter param;
param = new SqlParameter("#username", SqlDbType.VarChar);
param.Direction = ParameterDirection.Input;
param.Value = userNameTB;
cmd.Parameters.Add(param);
param = new SqlParameter("#pwd", SqlDbType.VarChar);
param.Direction = ParameterDirection.Input;
param.Value = passWordTB;
cmd.Parameters.Add(param);
try
{
cmd.ExecuteNonQuery();
cn.Close();
MessageBox.Show("Login");
}
catch (Exception ex)
{
MessageBox.Show("Invalid");
}
}
It runs, and I put in a breaker right after the commandtext line and so I see that it takes in the input from the textfields, but somehow it doesn't compare it with the username and password in the database.
I thank you for your help.
Cheers,
Essi
If it always shows as invalid, that should be an indication that your query is throwing an exception, since the "invalid" box is shown only if the exception is caught. What are the details of the exception?
If you read the documentation on SqlCommand.ExecuteNonQuery(), you'll note that in your case, it does nothing useful:
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected
by the command. When a trigger exists on a table being inserted or updated, the return
value includes the number of rows affected by both the insert or update operation and the
number of rows affected by the trigger or triggers. For all other types of statements, the
return value is -1. If a rollback occurs, the return value is also -1.
So ExecuteNonQuery() is not the correct method. I suspect that your exception is being thrown is related to the fact that you've executed a select statement, producing a result set that hasn't been processed, due to using ExecuteNonQuery().
As an aside, I would note that it is considered poor practice to use exceptions for flow-of-control program logic. Exceptions are for...exceptional conditions, not ordinary program logic. Further, when catching an exception, one should be as specific as possible. Otherwise, as you've discovered, you catch exceptions that shouldn't have been caught, which cause other problems.)
I'd do something like this instead:
static bool IsAuthenticated( string uid , string pwd )
{
if ( string.IsNullOrWhiteSpace(uid) ) throw new ArgumentNullException("uid") ;
if ( string.IsNullOrWhiteSpace(pwd) ) throw new ArgumentNullException("pwd") ;
bool authenticated ;
using ( SqlConnection cn = new SqlConnection("Data source=(local); Initial Catalog=INT422Assignment1; Integrated Security=SSPI;") )
using ( SqlCommand cmd = cn.CreateCommand() )
{
cmd.CommandType = CommandType.Text ;
cmd.CommandText = #"
SELECT authenticated = count(*)
FROM myLogin
WHERE userNameTB = #username
AND passWordTB = #pwd"
;
cmd.Parameters.AddWithValue( "#username" , uid ) ;
cmd.Parameters.AddWithValue( "#pwd" , pwd ) ;
cn.Open() ;
authenticated = ((int)cmd.ExecuteScalar()) > 0 ? true : false ;
cmd.ExecuteNonQuery();
cn.Close() ;
}
return authenticated ;
}
Use ExecuteScalar() The executenonquery doesn't return anything. or use SqlDataAdapter and fill in DataTable and see if there are any rows in the DataTable or use ExecuteScalar() to get the first item returned from the database. You need data returned from the database.
On the other hand I would use ASP.NET membership that already has user login/out function built in. I wouldn't build my own login logout webpage.
try
{
cmd.ExecuteNonQuery(); //this is for inserting or updating db
cn.Close();
MessageBox.Show("Login");
}
catch (Exception ex)
{
MessageBox.Show("Invalid");
}
try this instead using SqlDataReader
try{
SqlDataReader dr = cmd.ExecuteReader()
While dr.Read() {
string password = dr("pwd").ToString();
string username = dr("username").ToString();
}
}
EDIT:
try{
SqlDataReader dr = cmd.ExecuteReader();
If dr.HasRows() {
//Here is your code for good login
}
}
A sql query with no results does not throw an exception. You'll need to get the results and check if they are empty: if (res.MoveNext()).
I don't believe you need the # symbol in this code.
SqlParameter param;
param = new SqlParameter("username", SqlDbType.VarChar);
param.Direction = ParameterDirection.Input;
param.Value = userNameTB;
cmd.Parameters.Add(param);
The parameter name I believe should just be username same for pwd
Related
I need to insert a line in my question table and retrieve the inserted id. I initialize my sql command and execute it with ExecuteScalar(). I'm trying to convert the result of this method to int but I can not do it.
I tried to do that:
int result = Convert.ToInt32(Command.ExecuteScalar));
or
int result = (int)Command.ExecuteScalar();
but nothing work
here is my function
public int AddQuestionOrientation(Question questionForAdd)
{
try
{
con = new SqlConnection(connectionString);
con.Open();
SqlCommand command;
String sql = "";
sql = "INSERT INTO QUESTION VALUES(#Libelle,
#Bareme,2,#Filliere)";
SqlParameter param = new SqlParameter();
param.ParameterName = "#Libelle";
param.Value = questionForAdd.Libelle;
SqlParameter param2 = new SqlParameter();
param2.ParameterName = "#Bareme";
param2.Value = questionForAdd.Bareme;
SqlParameter param3 = new SqlParameter();
param3.ParameterName = "#Filliere";
param3.Value = questionForAdd.IdFiliere;
command = new SqlCommand(sql, con);
command.Parameters.Add(param);
command.Parameters.Add(param2);
command.Parameters.Add(param3);
int idQuestionInserted = (int)command.ExecuteScalar();
command.Dispose();
con.Close();
return idQuestionInserted;
}
catch(Exception ex)
{
return 0;
}
}
If I try with the cast (int), I have the message error:
Object reference not set to an instance of an object
If I try with the Convert.ToInt32, my variable "IdQuestionInserted" is equal to 0.
This is a big departure from where you started. But you have several issue going on there. You should use the USING statement around objects with the IDisposable interface (connections, commands, etc...).
This code is all untested but should be really close.
Start with creating a stored procedure so you can start creating layers in your application.
create Procedure Question_Insert
(
#Libelle varchar(50)
, #Bareme varchar(50)
, #Filliere varchar(50)
, #QuestionID int output
) as
set nocount on;
INSERT INTO QUESTION
(
Libelle
, Bareme
, Filliere
)
values
(
#Libelle
, #Bareme
, #Filliere
)
select #QuestionID = SCOPE_IDENTITY()
Then in your dotnet code you need to change up a few things to make it cleaner and more robust. Ideally you should do something better than simply return 0 when there is an error. It will be really tough to debug when something goes wrong if you simply return a 0. This is like an error message that says, "An error occurred". Pretty useless. Do something with the error. Capture the message to enable you to fix it.
public int AddQuestionOrientation(Question questionForAdd)
{
try
{
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
using (SqlCommand command = new SqlCommand("Question_Insert"))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#Libelle", SqlDbType.VarChar, 50).Value = questionForAdd.Libelle;
command.Parameters.Add("#Bareme", SqlDbType.VarChar, 50).Value = questionForAdd.Bareme;
command.Parameters.Add("#Filliere", SqlDbType.VarChar, 50).Value = questionForAdd.IdFiliere;
command.Parameters.Add("#QuestionID", SqlDbType.Int).Direction = ParameterDirection.Output;
command.ExecuteNonQuery();
return int.Parse(command.Parameters["#QuestionID"].Value.ToString());
}
}
}
catch (Exception ex)
{
return 0;
}
}
To get inserted id use SCOPE_IDENTITY() add SELECT CAST(scope_identity() AS int to command query to do
INSERT INTO QUESTION
VALUES(#Libelle, #Bareme, 2, #Filliere);
SELECT CAST(scope_identity() AS int;
this query will return inserted id for you.
I have an Oracle stored function which in Oracle is called as follows:
DECLARE
return_data varchar2(32767);
BEGIN
return_data := UCB_SYNC.GET_PROTEIN_DETAILS('PB0000007');
DBMS_OUTPUT.PUT_LINE(return_data);
END;
This works just fine so I now want to call it in C#; so I have the following code:
public string ExecuteStoredProcedure()
{
using (DbConnection cnn = GetNewConnection())
{
cnn.Open();
using (DbCommand cmd = cnn.CreateCommand())
{
cmd.CommandText = "ucb_sync.get_protein_details";
cmd.CommandType = CommandType.StoredProcedure;
DbParameter dbp = cmd.CreateParameter();
dbp.ParameterName = "protein_batch_id";
dbp.Value = "PB0000007";
dbp.DbType = DbType.String;
cmd.Parameters.Add(dbp);
DbParameter returnDbp = cmd.CreateParameter();
returnDbp.Direction = ParameterDirection.ReturnValue;
returnDbp.ParameterName ="result_data";
returnDbp.DbType = DbType.String;
cmd.Parameters.Add(returnDbp);
try
{
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
throw e;
}
return returnDbp.Value.ToString();
}
}
}
This executes but the first parameter (protein_batch_id) gets passed through as an empty string. I can see this from my logs and the exception that comes back from the Oracle also confirms this.
It's a simple question; can anyone see what I'm doing wring to cause the first parameter to get passed through as an empty string?
Thanks for your help; it's dark, late and I need to get this done before going home!
You need to set the BindByName property of the command to true.
To do this replace the line
using (DbCommand cmd = cnn.CreateCommand())
with
using (OracleCommand cmd = cnn.CreateCommand())
and then add the line
cmd.BindByName = true;
to the other lines that configure cmd.
I am trying to insert a record if requested prodName doesnot exist in database. If it exists I want to update the value of quantity attribute. I have used the following it neither inserts nor Updates any record. I get following exception:
ExecuteScalar requires an open and available Connection. The connection's current state is closed
This is the code
public static void manageStock(CompanyStock stock)
{
///// Check if record exists/////////
cmd = new SqlCommand("select count(*) from tblStock where prodName=#prodName", con);
cmd.Parameters.AddWithValue("#prodName", stock.prodName);
con.Open();
Int32 count = (Int32)cmd.ExecuteScalar(); //returns null if doesnt exist
con.Close();
if (count > 0)
{
cmd = new SqlCommand("update tblStock set quantity = #quantity where prodName=#prodName", con);
cmd.Parameters.AddWithValue("#prodName", stock.prodName);
cmd.Parameters.AddWithValue("#quantity", stock.quantity);
}
else
{
cmd = new SqlCommand("insert into tblStock(prodName,quantity) values (#prodName, #quantity)", con);
cmd.Parameters.AddWithValue("#prodName",stock.prodName);
cmd.Parameters.AddWithValue("#quantity",stock.quantity);
}
try
{
con.Open();
cmd.ExecuteNonQuery();
}
finally
{
con.Close();
}
}
}
Edited
I edited my code. It works fine now. I had to open my connection before executing ExecuteScalar But I want to know the standard way of writing this opening and closing stuff. It looks kind of haphazard. How can I improve this?
You can use Convert.ToInt32() method for converting the result into integer value.
if the value is null it converts it into 0.
Try This:
int count = Convert.ToInt32(cmd.ExecuteScalar());
Consider using MERGE clause in sql-server. Here is a good Microsoft article you can use.
What does it do when you step through the code?
In some SQL collations (Latin1_General_BIN for example), variables are case sensitive. In your first select statement you have #ProdName in your query and #prodName in your parameters collection. If you have a case sensitive collation, you're never getting past this part. Right-click on the database in Management Studio and click Properties to find the collation.
Error say that there's no connection.May u check first of all that issue so
Check connection and if is not null and exist at this point check it con.State = Open or any other value. I connection state is closed open it.But first of all where is connections declaration ? i don't see it in your code.
TRY THIS :
//USING THE STATEMNET USING IT WILL TAKE CARE TO DISPOSE CONNECTION AND PLACE TRY CATCH WITHIN PROCS
{
using (SqlConnection cnn = new SqlConnection(ConfigurationManager.AppSettings("connectionString"))) {
if (cnn.State == System.Data.ConnectionState.Closed)
cnn.Open();
using (SqlCommand cmd = new SqlCommand()) {
try {
cmd.Connection = cnn;
cmd.CommandText = "YOUR SQL STATEMENT";
int I = Convert.ToInt32(cmd.ExecuteNonQuery);
if (I > 0)
{
cmd.CommandText = "YOUR SQL STATEMENT";
//ADDITIONAL PARAMTERES
}
else
{
cmd.CommandText = "YOUR SQL STATEMENT";
//ADDITIONAL PARAMETERS
}
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
}
}
}
You can try this code. First write a stored procedure:
CREATE PROCEDURE sprocquanupdateinsert
#prodName nvarchar(250),
#quantity int
AS
BEGIN
UPDATE tblStock
SET quantity = #quantity
WHERE prodName = #prodName
IF ##ROWCOUNT = 0
INSERT INTO tblStock(prodName, quantity)
VALUES (#prodName, #quantity)
END
GO
Then in code behind you can use this
using (conn)
{
SqlCommand cmd = new SqlCommand("sprocquanupdateinsert", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#prodName", stock.prodName);
cmd.Parameters.AddWithValue("#quantity", stock.quantity);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
I have this stored procedure:
create procedure sp_findMaxEmployee
#maxID as varchar(10) OUTPUT
as
SET #maxID = (SELECT MAX(e_ID) FROM Employee)
go
I try to register an output parameter like this:
public string generateID()
{
connection = new SqlConnection(connectionStr);
cmd = new SqlCommand("sp_findMaxEmployee", connection);
SqlParameter param = new SqlParameter();
param.ParameterName = "#maxID";
param.Direction = ParameterDirection.Output;
param.SqlDbType = SqlDbType.VarChar;
cmd.Parameters.Add(param);
connection.Open();
cmd.ExecuteNonQuery();
connection.Close();
return cmd.Parameters["#maxID"].Value.ToString();
}
I tried to execute this procedure in SQL and it return right value, but when I execute project in debug mode, it shows me error:
String[0]: the Size property has an invalid size of 0.
Null value? Can you help me, thank you so much!
Assuming e_ID is a integer, you can just perform a SELECT and ExecuteScalar to return a single value:
create procedure sp_findMaxEmployee
as
SELECT MAX(e_ID) FROM Employee
go
Then in code, something like:
public string generateID()
{
connection = new SqlConnection(connectionStr);
cmd = new SqlCommand("sp_findMaxEmployee", connection);
connection.Open();
var maxId = cmd.ExecuteScalar();
connection.Close();
return maxId.ToString();
}
Finally, there's probably a deeper question as to why you are returning the last ID, hopefully it's not to get the next available ID, which you should let SQL do on your behalf by letting it auto-increment.
Little Tweak for SP
The Tweak is not necessary but it looks better this way :) and also please avoid using sp_ prefix for your stored procedures. Use usp_ instead.
create procedure usp_findMaxEmployee
#maxID as varchar(10) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT #maxID = MAX(e_ID) FROM Employee;
END
Calling from Code
public string generateID()
{
SqlConnection conn = new SqlConnection(connectionStr);
SqlCommand cmd = new SqlCommand("usp_findMaxEmployee", conn);
cmd.CommandType = CommandType.StoredProcedure;
// set up the parameters
cmd.Parameters.Add("#maxID", SqlDbType.VarChar, 10).Direction = ParameterDirection.Output;
// open connection and execute stored procedure
conn.Open();
cmd.ExecuteNonQuery();
// read output value from #maxID
String maxID = Convert.ToString(cmd.Parameters["#maxID"].Value);
conn.Close();
return maxID;
}
Note
Use the using block of Try/Catch/Finnaly blocks to close connection if anything goes wrong.
You need to specify a .Size for your parameter. Your stored procedure specifies an output of varchar(10), so you should set the param.Size = 10;
You need to specify that cmd.CommandType = CommandType.StoredProcedure, the default CommandType is CommandType.Text
Make those changes and your method works as you intended.
I am developing a web app and have encountered a problem. I need to insert username and ip address into a SQL database table "log" when someone tries (successfully or unsuccessfully) to login. ID, time and date are inserted automatically...
For some reason I am unable to get it working in my login form. INSERT statement works ok if I initiate it from another form, but I can't get it working together with the SELECT statement I use for checking login credentials.
I have tried different solutions, but none of them inserts data into the table... It does not throw an error, it just doesn't insert a new row into "log" table.
Any help is appreciated. :)
protected void btnLog_Click(object sender, EventArgs e)
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["dbConn"].ToString()))
{
string username = null;
string password = null;
string ipAddress = null;
SymCryptography cryptic = new SymCryptography();
SqlCommand cmdSelect = new SqlCommand();
SqlCommand cmdLog = new SqlCommand();
SqlDataReader myReader = null;
cmdSelect.Connection = conn;
cmdLog.Connection = conn;
cmdSelect.CommandText = "SELECT * FROM uporabniki WHERE up_ime=#up_ime AND geslo=#geslo";
cmdSelect.CommandType = CommandType.Text;
cmdLog.CommandText = "INSERT INTO log (up_ime, ip) VALUES (#up_ime, #ip)";
cmdLog.CommandType = CommandType.Text;
cmdSelect.Parameters.Add("#up_ime", SqlDbType.NVarChar, 20).Value = tbUsr.Text;
cmdSelect.Parameters.Add("#geslo", SqlDbType.NVarChar, 20).Value = cryptic.Encrypt(tbPwd.Text);
cmdLog.Parameters.Add("#up_ime", SqlDbType.NVarChar, 20).Value = tbUsr.Text;
cmdLog.Parameters.Add("#ip", SqlDbType.NVarChar, 20).Value = ipAddress;
conn.Open();
try
{
//cmdLog.ExecuteNonQuery(); I tried it here, but it doesn't work
myReader = cmdSelect.ExecuteReader();
if (myReader.Read())
{
username = myReader["up_ime"].ToString();
password = myReader["geslo"].ToString();
Session["rights"] = myReader["pravice"];
Session["login"] = "OK";
pravice = true;
}
myReader.Close();
//cmdLog.ExecuteNonQuery(); I tried it here, but it doesn't work
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
conn.Close();
}
//I tried to open connection again, but stil INSERT does not work
/* using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["dbConn"].ToString()))
{
string ipAddress = null;
SqlCommand cmdLog = new SqlCommand();
cmdLog.Connection = conn;
cmdLog.CommandText = "INSERT INTO log (up_ime, ip) VALUES (#up_ime, #ip)";
cmdLog.CommandType = CommandType.Text;
cmdLog.Parameters.Add("#up_ime", SqlDbType.NVarChar, 20).Value = tbUsr.Text;
cmdLog.Parameters.Add("#ip", SqlDbType.NVarChar, 20).Value = ipAddress;
conn.Open();
try
{
cmdLog.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
conn.Close();
}
if (pravice == true)
{
Response.Redirect("Default.aspx");
}
else
{
Response.Redirect("Login.aspx");
}*/
}
Your not executing your cmdLog.ExecuteNonQuery(); statement.
Also, try opening a query window in your sql database and run the following against it.
INSERT INTO log (up_ime, ip) VALUES (<some time>, <test ip text>)
If the error lies in sql server you should be returned an error message stating if the problem lies withing SQL Server.
Also try changing:
cmdLog.Parameters.Add("#up_ime", SqlDbType.NVarChar, 20).Value = tbUsr.Text;
cmdLog.Parameters.Add("#ip", SqlDbType.NVarChar, 20).Value = ipAddress;
To:
cmdLog.Parameters.Add("#up_ime", tbUsr.Text);
cmdLog.Parameters.Add("#ip", ipAddress);
Check whether your connection string value is ok. Also put a break point on the:
conn.Open();
See whether you get an error?
If not then that means your connectionstring is ok.
Uncomment this line after Try{}
//cmdLog.ExecuteNonQuery(); I tried it here, but it doesn't work
and put a break point on it .. see whether you get an error?
Also from your code I can see that you are inserting a null ipaddress value into the table. See whether the column in your database is allowed to accept nulls??
The using statement will clean up the connection in the garbage collection process which happens at an indeterminable time. This is why 1 of the orders of execution you've tried doesn't work (the connection may not be usable). Suggest you do either:
Both operations within 1 using (connection), make sure you close the connection in a finally() block and re-init your command against the newly opeend connection.
Have 2 different connections conn1 and conn2 and perform the separate operations in each.
EDIT: I have re-read and you say no errors occur? - try checking the result of ExecuteNonQuery (it returns an integer to show the number of rows that have been affected - if this is zero there is a problem with your insert statement).