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).
Related
I'm trying to delete record from data base MSSQL by entering the ID and hit delete btn. i didn't get any error and it give recorded deleted successful but once i check database i see the record doesn't deleted
protected void btnDelete_Click(object sender, EventArgs e)
{
try
{
if (txtImgID.Text == "")
{
Response.Write("Enter Image Id To Delete");
}
else
{
SqlCommand cmd = new SqlCommand();
SqlConnection con = new SqlConnection();
con = new SqlConnection(ConfigurationManager.ConnectionStrings["GMSConnectionString"].ConnectionString);
con.Open();
cmd = new SqlCommand("delete from certf where id=" + txtImgID.Text + "", con);
lblsubmitt.Text = "Data Deleted Sucessfully";
}
}
catch (Exception)
{
lblsubmitt.Text = "You haven't Submited any data";
}
}
var idToDelete = int.Parse(txtImgID.Text); // this is not necessary if the data type in the DB is actually a string
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["GMSConnectionString"].ConnectionString))
using (SqlCommand cmd = new SqlCommand("DELETE FROM [certf] WHERE id = #id", con))
{
// I am assuming that id is an integer but if it is a varchar/string then use the line below this one
// cmd.Parameters.Add("#id", SqlDbType.VarChar, 100).Value = txtImgID.Text;
cmd.Parameters.Add("#id", SqlDbType.Int32).Value = idToDelete;
cmd.ExecuteNonQuery();
}
You need to call ExecuteNonQuery which executes the query against the database.
Always use parameters instead of string concatenation in your queries. It guards against sql injection and ensures you never has issues with strings that contain escape characters.
I did not include any error handling or return messages but do note that you are throwing away all the good stuff in your excetion handler's catch block, you will never know why a query failed after this has executed.
[SOLVED]
SOLUTION: When you execute the program inside visual studio it won't commit the changes to the database, but instead, it will work with a copy. When you deploy your program to an executable file, this executable is able to modify permanently your database. Hope this helps anyone :)
As i've said in this question HERE, I can't save the changes of my dataset to my DataBase. I tried to follow this tutorial HERE and couldn't get it to work either: The program compiles and executes, but the new data isn't committed to the DB. Here's the code I wrote following the turorial.
//METHOD INSIDE MY SIGN UP WINDOWS FORM
public static SqlDataAdapter GetuserRecord()
{
SqlConnection connection = new SqlConnection("Data Source=(LocalDB)\\v11.0;AttachDbFilename=|DataDirectory|\\DatabaseJogo.mdf;Integrated Security=True");
string query = "Select * from dbo.[user]";
SqlCommand command = new SqlCommand(query, connection);
connection.Open();
SqlDataAdapter adp = new SqlDataAdapter(command);
MessageBox.Show("CONNECTION SUCCESFUL");
return adp;
}
//WHEN MY SIGN UP BUTTON IS CLICKED:
SqlDataAdapter adp = GetuserRecord();
DataSet ds = new DataSet();
adp.Fill(ds);
DataRow newRow = ds.Tables[0].NewRow();
newRow["login"] = loginText.Text.Trim();
newRow["name"] = nameText.Text.Trim();
newRow["age"] = int.Parse(ageText.Text.Trim());
newRow["graphicsScore"] = trackBar1.Value;
newRow["storyScore"] = trackBar2.Value;
newRow["gameplayScore"] = trackBar3.Value;
newRow["password"] = passwordText.Text.Trim();
newRow["isAdmin"] = isAdmin.Checked;
newRow["sex"] = sex.Text.Trim();
ds.Tables[0].Rows.Add(newRow);
SqlCommandBuilder commandBuilder = new SqlCommandBuilder(adp);
adp.UpdateCommand = commandBuilder.GetUpdateCommand(true);
adp.InsertCommand = commandBuilder.GetInsertCommand(true);
adp.DeleteCommand = commandBuilder.GetDeleteCommand(true);
adp.Update(ds);
EDIT: CHANGED THE CODE TO A NEW ONE, BUT THE PROBLEM IS STILL THE SAME. IF YOU WANT TO TAKE A LOOK, HERE IT IS:
//TRY 3 SQL
//https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqltransaction.commit(v=vs.110).aspx
SqlConnection connection = new SqlConnection("Data Source=(LocalDB)\\v11.0;AttachDbFilename=|DataDirectory|\\DatabaseJogo.mdf;Integrated Security=True");
connection.Open();
SqlCommand command = connection.CreateCommand();
SqlTransaction transaction;
transaction = connection.BeginTransaction("SIGNUP");
command.Connection = connection;
command.Transaction = transaction;
try
{
command.CommandText = "INSERT INTO [user] ([login], [name], [age], [graphicsScore], [storyScore], [gameplayScore], [password], [isAdmin], [sex]) VALUES (#login, #name, #age, #graphicsScore, #storyScore, #gameplayScore, #password, #isAdmin, #sex);";
command.Parameters.Add("#login", SqlDbType.NChar, 50).Value = loginText.Text.Trim();
command.Parameters.Add("#name", SqlDbType.NChar, 50).Value = nameText.Text.Trim();
command.Parameters.Add("#age", SqlDbType.Int).Value = int.Parse(ageText.Text.Trim());
command.Parameters.Add("#graphicsScore", SqlDbType.Int).Value = trackBar1.Value;
command.Parameters.Add("#storyScore", SqlDbType.Int).Value = trackBar2.Value;
command.Parameters.Add("#gameplayScore", SqlDbType.Int).Value = trackBar3.Value;
command.Parameters.Add("#password", SqlDbType.NChar, 50).Value = passwordText.Text.Trim();
command.Parameters.Add("#isAdmin", SqlDbType.Bit).Value = isAdmin.Checked;
command.Parameters.Add("#sex", SqlDbType.NChar).Value = sex.Text.Trim();
command.ExecuteNonQuery();
transaction.Commit();
MessageBox.Show("COMMITTED");
}
catch (Exception expt)
{
MessageBox.Show(expt.Message);
try
{
transaction.Rollback();
}
catch (Exception ex2)
{
// This catch block will handle any errors that may have occurred
// on the server that would cause the rollback to fail, such as
// a closed connection.
MessageBox.Show("Rollback Exception Type: " + ex2.GetType());
MessageBox.Show(" Message: " + ex2.Message);
}
}
//connection.UpdateDatabase(ds);
connection.Close();
In order to Updateupdate the data on the database your SqlDataAdapter need to have its InsertCommand, UpdateCommand, DeleteCommand properties set.
So, try the below code:
ds.Tables[0].Rows.Add(newRow);
SqlCommandBuilder commandBuilder = new SqlCommandBuilder(adp);
adp.DeleteCommand = commandBuilder.GetDeleteCommand(true);
adp.UpdateCommand = commandBuilder.GetUpdateCommand(true);
adp.InsertCommand = commandBuilder.GetInsertCommand(true);
adp.Update(ds.Tables[0]);
//connection.UpdateDatabase(ds);
connection.Close();
Edit:
The Update method takes the name of a DataSet and a table. The DataSet for us is ds, which is the one we passed in to our UpdateDatabase method when we set it up. After a dot, you type the name of a table in your dataset.
I am going thru the same thing:
I can create the dataset, then insert, update and delete, then have the changed dataset's data displayed. This works so far as expected as all the changes of the dataset show. But you can run this again and again, so: the data in the underlying database is not changed.
Either some final commit somewhere is missing or it just does not work as it should and as these methods are not current any more nobody cares.
Sincerly
Andi
So I want to create a line graph with data from a MySQL table and I've managed to draw one using the code below.
However, I want to pass a variable 'moduleID' to the MySQL query and I have done so, however, I'm not sure if this is the most appropriate way to do so. Should I pass a parameter instead and if so, how do I do that?
protected void chart(int moduleID)
{
string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
MySqlConnection conn = new MySqlConnection(connStr);
string comm = "SELECT * FROM scores WHERE module_id=" + moduleID.ToString();
MySqlDataAdapter dataAdapter = new MySqlDataAdapter(comm, conn);
DataSet ds = new DataSet();
Chart1.ChartAreas["ChartArea1"].AxisX.MajorGrid.Enabled = false;
Chart1.ChartAreas["ChartArea1"].AxisY.MajorGrid.Enabled = false;
Chart1.ChartAreas["ChartArea1"].AxisX.Minimum = 1;
Chart1.ChartAreas["ChartArea1"].AxisX.LabelStyle.Enabled = false;
Chart1.ChartAreas["ChartArea1"].AxisX.Title = "time";
Chart1.ChartAreas["ChartArea1"].AxisY.Minimum = 0;
Chart1.ChartAreas["ChartArea1"].AxisY.Maximum = 100;
Chart1.ChartAreas["ChartArea1"].AxisY.Title = "%";
Chart1.ChartAreas["ChartArea1"].AxisY.TextOrientation = TextOrientation.Horizontal;
try
{
conn.Open();
dataAdapter.Fill(ds);
Chart1.DataSource = ds;
Chart1.Series["Series1"].YValueMembers = "score";
Chart1.DataBind();
}
catch
{
lblError.Text = "Database connection error. Unable to obtain data at the moment.";
}
finally
{
conn.Close();
}
}
You are right. Concatenating strings to form a query is prone to SQL injection. Use parameters like:
string comm = "SELECT * FROM scores WHERE module_id=#module_id";
MySqlCommand mySqlCommand = new MySqlCommand(comm,conn);
mySqlCommand.Parameters.Add(new MySqlParameter("#module_id", module_id));
MySqlDataAdapter dataAdapter = new MySqlDataAdapter(mySqlCommand);
You should also enclose your connection and command object with using statement. This will ensure proper disposal of resource.
Also an empty catch is very rarely useful. You should catch specific exception first and then the base exception Exception in an object. Use that object to log the exception information or show in your error message. This will provide you help in debugging your application.
Step1: Create stored Procedure
CREATE PROCEDURE SelectScore
(#moduleID NCHAR(50))AS
SELECT * FROM scores WHERE module_id=#moduleID
Step2: Call the stored Procedure from Code
string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connStr )) {
conn.Open();
// 1. create a command object identifying the stored procedure
SqlCommand cmd = new SqlCommand("SelectScore", conn);
// 2. set the command object so it knows to execute a stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// 3. add parameter to command, which will be passed to the stored procedure
cmd.Parameters.Add(new SqlParameter("#moduleID ", moduleID ));
// execute the command
using (SqlDataReader rdr = cmd.ExecuteReader()) {
// iterate through results, printing each to console
while (rdr.Read())
{
..
}
}
}
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
What is the easiest and most SQL-like way to insert textbox values into a SQL Server table? I found several ways, and all of them are too complicated for this simple thing I want to do.
If LINQ is too foreign for you, you can still do things the old-fashioned way:
string statement = "INSERT INTO mytable(mycolumn) VALUES (#text)";
SqlCommand command = new SqlCommand(statement);
command.Parameters.AddWithValue("#text", myTextBox.Text);
try{
SqlConnection connection = new SqlConnection(myConnectionString);
connection.Open();
command.Connection = connection;
command.ExecuteNonQuery();
} catch {
//do exception handling stuff
}
Edit: Here's another version that uses using to ensure that messes are cleaned up:
string statement = "INSERT INTO mytable(mycolumn) VALUES (#text)";
using(SqlCommand command = new SqlCommand(statement))
using(SqlConnection connection = new SqlConnection(myConnectionString)) {
try{
command.Parameters.AddWithValue("#text", myTextBox.Text);
connection.Open();
command.Connection = connection;
command.ExecuteNonQuery();
} catch {
//do exception handling stuff
}
}
If you want to do something quickly, use LINQ to SQL. It will take care of your Data Access Layer & Business objects.
Just go to LINQ to SQL Classes on Visual Studio & map your SQL server and add any tables you want to it.
Then you can use the objects it creates in your code behind to update values from textboxes.
http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx
public string ConnectionString
{
get
{
//Reading connection string from web.config
return ConfigurationManager.ConnectionStrings["ConnectionName"].ConnectionString;
}
}
public bool InsertEmployee()
{
bool isSaved = false;
int numberOfRowsAffected = 0;
string query = #"INSERT INTO Employee(EmployeeName, EmailAddress)
VALUES (#EmployeeName, #EmailAddress);
SELECT ##IDENTITY AS RowEffected";
SqlCommand cmd = new SqlCommand();
cmd.CommandText = query;
cmd.CommandType = System.Data.CommandType.Text;
cmd.Parameters.Add(new SqlParameter("#EmployeeName", txtEmployeeName.Text));
cmd.Parameters.Add(new SqlParameter("#EmailAddress", txtEmailAddress.Text));
try
{
using (SqlConnection cn = new SqlConnection(ConnectionString))
{
cmd.Connection = cn;
cn.Open();
object result = cmd.ExecuteScalar();
isSaved = Convert.ToInt32(result) > 0 ? true : false;
}
}
catch (Exception ex)
{
isSaved = false;
}
return isSaved;
}
But, in multiple layer or multi-tier application you do need to create DTO(Data Transfer Object) to pass the data from layer to layer(or tier to tier)
Here's a simple way to do it. It looks complex because of the number of rows: Inserting Data in SQL Database