I'm trying to make my first steps in databases used with WPF. The problem is that once I start the application, I get an error saying
Invalid Object - "tblUser"
where tblUser is the name of a table.
I made sure that table name is correct, tried creating another table to see whether it changes anything. All the permissions are granted to manipulate the table.
private void Submit_OnClick(object sender, RoutedEventArgs e)
{
SqlConnection sqlCon = new SqlConnection(#"Server=localhost\SQLEXPRESS;Database=master;Trusted_Connection=True;");
try
{
if (sqlCon.State == ConnectionState.Closed)
sqlCon.Open();
String query = "SELECT COUNT(1) FROM tblUser WHERE Username = #Username AND Password = #Password";
SqlCommand sqlCmd = new SqlCommand(query, sqlCon);
sqlCmd.Parameters.AddWithValue("#Username",txtUsername.Text);
sqlCmd.Parameters.AddWithValue("#Password", txtPassword.Text);
int count = Convert.ToInt32(sqlCmd.ExecuteScalar());
if (count == 1)
{
MainWindow dashboard = new MainWindow();
dashboard.Show();
this.Close();
}
else
{
MessageBox.Show("Username or password does not exist");
}
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
}
finally
{
sqlCon.Close();
}
}
First I create a connection to the database. Next step is I would like to check whether connection is closed, if it is I'm opening it. Then it looks like something went wrong with the SQL query because it seems not to recognise tblUser and sees it as an invalid one.
tblUser is certainly not in the master database. The asterisks are not part of SQL. I am surprised that the error message doesn't complain about that at first
Related
I am currently working on building an attendance tracker that will take the user's input data and add it to a database table. I'm running into an issue where my connection string will not connect to the database? I've copied it directly as is, and even tried a few different tutorials with alternative ways with no success. This is for an assignment however, our SQL portion was quite small and I'm not sure where to go from here. Please let me know if something in my code needs revisited.
When I run the code I get the "unable to connect" exception I created below. I need it to run and add the user input to the table.
I have also noticed that my database connection often disconnects unless I refresh, is this common?
namespace AttendanceTracker
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void signInButton_Click(object sender, EventArgs e)
{
string connectionString = null;
connectionString = #"Data Source=(LocalDB)\MSSQLLocalDB; AttachDbFilename = C:\Users\soupy\Desktop\AttendanceTracker\AttendanceTrackerDatabase.mdf; Integrated Security = SSPI";
SqlConnection con = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = ("INSERT into AttendanceTrackerDatabase VALUES (#studentName,#studentID,#Date,#class)");
cmd.Parameters.AddWithValue("#Student_Name", nameTextBox.Text);
cmd.Parameters.AddWithValue("#Student_ID", studentIDTextBox.Text);
cmd.Parameters.AddWithValue("#Class", classDropDown.Text);
cmd.Parameters.AddWithValue("#Date", attendanceDate.Value);
try
{
con.Open();
cmd.ExecuteNonQuery();
MessageBox.Show("Your sign in has been recorded successfully!");
con.Close();
}
catch (Exception ex)
{
MessageBox.Show("Unable to open attendance tracker for updating.");
}
}
When using Parameter objects, you should ensure that the variable names are consistent.
Please modify your code as follows
cmd.CommandText = ("INSERT into AttendanceTrackerDatabase VALUES (#studentName,#studentID,#Date,#class)");
cmd.Parameters.AddWithValue("#studentName", nameTextBox.Text); // Modified to "studentName"
cmd.Parameters.AddWithValue("#studentID", studentIDTextBox.Text); // Modified to "studentID"
cmd.Parameters.AddWithValue("#Date", attendanceDate.Value);
cmd.Parameters.AddWithValue("#class", classDropDown.Text); // Modified to "class"
So, I am new to VS and C#, I am self-teaching to get a better understanding of the back-end of the product I work with. I have created a small database with some information and a Login form. Everything appears to compile correctly but is that the security way to do that or there is another way,
any help is appreciated. Thanks.
private void button2_Click(object sender, EventArgs e)
{
SqlCommand cmd = new SqlCommand("select * from tbladmin where username=#username and password=#password", sqlcon);
cmd.Parameters.AddWithValue("#username", txtusername.Text);
cmd.Parameters.AddWithValue("#password", txtpassword.Text);
SqlDataAdapter sda = new SqlDataAdapter(cmd);
DataTable dtbl = new DataTable();
sda.Fill(dtbl);
try
{
if (dtbl.Rows.Count > 0)
{
if (dtbl.Rows[0]["role"].ToString() == "Admin")
{
SqlCommand cmd2 = new SqlCommand("select date from tbladmin where username=#username and password=#password", sqlcon);
cmd2.Parameters.AddWithValue("#username", txtusername.Text);
cmd2.Parameters.AddWithValue("#password", txtpassword.Text);
SqlDataAdapter sda2 = new SqlDataAdapter(cmd2);
DataTable dss = new DataTable();
sda2.Fill(dss);
String value2 = dss.Rows[0][0].ToString();
DateTime date = DateTime.Parse(dss.Rows[0][0].ToString());
Class1.Txtusername = txtusername.Text;
Debug.WriteLine("value is : " + value2);
if (date.AddDays(90) < DateTime.Now)
{
Changpassad obj2 = new Changpassad();
this.Hide();
obj2.Show();
}
else
{
calladmin obj = new calladmin(dss.Rows[0][0].ToString());
this.Hide();
obj.Show();
}
}
}
else if (dtbl.Rows.Count == 0)
{
SqlCommand cmd3 = new SqlCommand("select date from tblcallcenter where username=#username and password=#password", sqlcon);
cmd3.Parameters.AddWithValue("#username", txtusername.Text);
cmd3.Parameters.AddWithValue("#password", txtpassword.Text);
SqlDataAdapter sda2 = new SqlDataAdapter(cmd3);
DataTable dss = new DataTable();
sda2.Fill(dss);
String value2 = dss.Rows[0][0].ToString();
DateTime date = DateTime.Parse(dss.Rows[0][0].ToString());
Debug.WriteLine("value is : " + value2);
if (date.AddDays(90) < DateTime.Now)
{
Changpass obj2 = new Changpass()/;
this.Hide();
obj2.Show();
}
else
{
SqlCommand cmd4 = new SqlCommand("select user_id , username from tblcallcenter where username=#username and password=#password", sqlcon);
cmd4.Parameters.AddWithValue("#username", txtusername.Text);
cmd4.Parameters.AddWithValue("#password", txtpassword.Text);
SqlDataAdapter From_sda = new SqlDataAdapter(cmd4);
DataTable From_ds = new DataTable();
From_sda.Fill(From_ds);
String value1 = From_ds.Rows[0][1].ToString();
int id = int.Parse(From_ds.Rows[0][0].ToString());
Debug.WriteLine("value is : " + value1);
Class1.Txtusername = txtusername.Text;
this.Hide();
SqlCommand cmd5 = new SqlCommand("select [from], Take from tblcallcenter where username=#username and password=#password", sqlcon);
cmd5.Parameters.AddWithValue("#username", txtusername.Text);
cmd5.Parameters.AddWithValue("#password", txtpassword.Text);
SqlDataAdapter sda1 = new SqlDataAdapter(cmd5);
DataTable ds = new DataTable();
sda1.Fill(ds);
Callcenter1 obj = new Callcenter1(ds.Rows[0][0].ToString(), ds.Rows[0][1].ToString());
this.Hide();
obj.Show();
}
}
else
{
MessageBox.Show("Invalid Login try checking Useraname Or Password !", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception)
{
MessageBox.Show("Invalid Login try checking Useraname Or Password !", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
1. Don't forget the Single responsibility principle
The responsibility of your form is only UI presentation. Should your form know how you store your data? Is your form responsible to know when user should change their password? No.
Each class should have one single responsibility. You could have an AuthenticationService class responsible to authenticate the user, and an UserRepository class to store/retrieve users in the database. For example this could be your button2 click handler:
private void button2_Click(object sender, EventArgs e)
{
var authenticationService = new AuthenticationService(sqlcon);
try
{
var user = authenticationService.AuthenticateUser(txtusername.Text, txtpassword.Text);
if (user.Date.AddDays(90) < DateTime.UtcNow)
{
Changpassad obj2 = new Changpassad();
this.Hide();
obj2.Show();
return;
}
if (user.IsAdmin)
{
calladmin obj = new calladmin(user);
this.Hide();
obj.Show();
}
else
{
Callcenter1 obj = new Callcenter1(user);
this.Hide();
obj.Show();
}
}
catch (Exception)
{
MessageBox.Show("Invalid Login try checking Useraname Or Password !", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
You could take the principle even further and have your methods also have a single responsibility. For example, in the code above, I'd still extract the code checking if the passwords needs to be changed and the code responsible to open the correct form.
You already uses parameters in you SQL query. Good. You're resistant to SQL injection.
Once you're familiar, I also recommend looking into ORMs like Entity Framework to facilitate the process.
2. Don't store plaintext password in database
Seriously. Never do that.
Always try to avoid managing users password. If you absolutely must, there are built-in classes in .Net framework to handle that. Here is some links, but a quick search should yield many more.
Quickstart: Add sign-in with Microsoft to an ASP.NET web app
Introduction to Identity on ASP.NET Core
If for some reasons you don't use theses and decide to manage password yourself. You need to find a cryptographically secure hashing algorithm (not md5 like in the other answer). And you need to use an unique "salt" for each password you hash. I'll leave these link here since it's out of scope of your current question:
-Hash passwords in ASP.NET Core
-Difference between Encoding, Encryption and Hashing
3. Give significant name to your variable.
What is button2? What is obj2? What does ds.Rows[0][0].ToString() represent? You should try to give representative name to your variable. How about btnLogin, callAdminForm, ...
While we're here I recommend you read C# General Naming Conventions. For example, naming convention for classes is PascalCase. It should be CallAdmin not calladmin.
4. Why do you have user/password stored in multiple tables?
Why are users stored in both tbladmin and tblcallcenter?
How about a single tblUsers and either a column or a related table specifying the user role? This will be easier to maintain in the long run. Why do something twice when you could do it once?
You can care about:
1- Hashing the password using something like:
CONVERT(VARCHAR(32), HashBytes('MD5', 'password'), 2)
2- Compare exact letters case upper or lower.
Select * from tblcallcenter where password= #password COLLATE Latin1_General_CS_AS
using case sensitive collation to be sure the password is same
3- You can use some new database c# technologies like Entity Framework or older like Typed Dataset or Linq to sql it's easy and quick to develop.
Entity Framework, Typed Dataset, Linq to SQL
It is not good idea to mix everything in one class. Try to split this task into several items:
validate user input (it could be separate method in same class)
separate class (or at least method) which handles DB. You should pass login information and get result (true/false is enough)
notification of result - display message about empty username/password, about incorrect login
Believe me, it would be more easily for you to develop it further. Good luck :)
I am a noob attempting to create a login page where the user enters their username and password that is already in the sqldatabase connected to the textboxes/button/form. The below code is my best attempt at doing so, but upon debugging it throws catch despite the textbox values entered being registered in the sql database. If any additional information is needed please ask.
private bool compareStoD(string teststring1, string teststring2)
{
return String.Compare(teststring1, teststring2, true, System.Globalization.CultureInfo.InvariantCulture) == 0 ? true : false;
}
private void button1_Click_1(object sender, EventArgs e)
{
try
{
SqlConnection connection = new SqlConnection(#"Data Source=DESKTOP-P3JSE1C;Initial Catalog=logins;Integrated Security=True");
connection.Open();
SqlCommand checker = new SqlCommand("SELECT COUNT (*) from users WHERE username='" + textBox1.Text + "'AND pssword='" + textBox3.Text + "'", connection);
SqlDataReader reader = checker.ExecuteReader();
string usernameText = textBox1.Text;
string psswordText = textBox3.Text;
while (reader.Read())
{
if (this.compareStoD(reader["username"].ToString(), textBox1.Text) && // replace textbox1.Text with text string usernameText
this.compareStoD(reader["pssword"].ToString(), textBox3.Text)) //replace textbox3.Text with text string psswordText
{
main wen = new main();
wen.Show();
}
}
reader.Close();
connection.Close();
}
catch
{
MessageBox.Show("Incorrect password or username.");
}
}
It is most likely throwing an exception because your query is asking for the count but then you are reading columns username and password which do not exist in the reader. This is your query:
SELECT COUNT (*)
Change that to this:
SELECT username, password ...
Also, unless you want every savvy user to access your application, use SqlParameter to avoid SQL Injection
Another Suggestion
I am not sure what main is, my assumption it is some window, but I would not show it where you are showing right now. Try to close the reader as soon as possible and then show the window if the user is authenticated like this.
bool userIsAuthenticated = false;
if (reader.Read())
{
// if a row was returned, it must be the row for the user you queried
userIsAuthenticated = true;
}
reader.Close();
connection.Close();
// Now that the reader is closed, you can show the window so the reader does not stay
// open during the duration of the main window
if (userIsAuthenticated)
{
main wen = new main();
wen.Show();
}
Select count returns the count not the row, if you want the row itself change to select username, password instead of select count(*) . See this link
There is over work being done by your code. You are querying the database by comparing the username and password values from UI to the values in the table. And once and if values are retrieved from the database you are again comparing value from UI to the values coming from the database. This is unnecessary.
The query will return the values only if values match in the database so you don't need to compare them again. So method compareStoD is not required at all.
The button1_Click can be changed as following to make it simpler.
private void button1_Click_1(object sender, EventArgs e)
{
try
{
SqlConnection connection = new SqlConnection(#"Data Source=DESKTOP-P3JSE1C;Initial Catalog=logins;Integrated Security=True");
connection.Open();
SqlCommand checker = new SqlCommand("SELECT COUNT (*) from users WHERE username=#userName AND pssword = #password", connection);
checker.Parameters.Add(new SqlParameter("#userName", textBox1.Text));
checker.Parameters.Add(new SqlParameter("#password", textBox3.Text));
var count = Convert.ToInt32(checker.ExecuteScalar());
connection.Close();
if(count > 0)
{
main wen = new main();
wen.Show();
}
else
{
MessageBox.Show("Incorrect password or username.");
}
}
catch
{
MessageBox.Show("Incorrect password or username.");
}
}
Also one good practice while supplying values from Textbox, you should use Textbox.Text.Trim() which helps in eliminating the spaces at the beginning and end. These spaces can create a problem in later stage.
private void btnLogin_Click(object sender, EventArgs e)
{
{
Connections.con.Open();
string login = "SELECT ID, Username, [Password] FROM Employee";
OleDbCommand command = new OleDbCommand(login, Connections.con);
command.Connection = Connections.con;
command.Parameters.AddWithValue("#?", txtLUser.Text.ToString());
command.Parameters.AddWithValue("#?", txtLPass.Text.ToString());
OleDbDataReader reader = command.ExecuteReader();
int count = 0;
while (reader.Read())
{
count = count + 1;
break;
}
if (count == 1)
{
MessageBox.Show("Login Successful.");
this.Close();
}
else
{
MessageBox.Show("Please enter a valid Username or Password");
}
Connections.con.Dispose();
Connections.con.Close();
MessageBox.Show("Thank you for using this Simple Login/Registration Form.");
}
It always Logs in whenever i click Login Button and i haven't even typed anything in the user/pass textbox and there is no blank registered in my access database
any advice?
You're not actually checking the username and password. Look at the database query:
"SELECT ID, Username, [Password] FROM Employee"
This will select every record from the Employee table. Then you check those records:
while (reader.Read())
{
count = count + 1;
break;
}
if (count == 1)
{
MessageBox.Show("Login Successful.");
this.Close();
}
According to this logic, as long as any record exists in the Employee table, the login is successful.
You probably want to check only for records which match the supplied credentials. Something like this:
"SELECT [ID], [Username], [Password] FROM [Employee] WHERE [Username] = #? AND [Password] = #?"
(I'm guessing on the parameter syntax based on how you add the parameters, since I'm not familiar with MS Access syntax. But hopefully you get the idea.)
Also, and this is important, you appear to be storing user passwords in plain text. This is an extremely terrible thing to do. Please hash passwords appropriately so that they can't be read as plain text.
Additionally, you appear to be using a shared connection object:
Connections.con.Open();
This is going to cause a whole host of problems. It's a lot simpler and more stable to create the connection object within the scope of the method which uses it. Basically, a connection object should be created, used, and disposed in a very tight scope and should not leak outside of that scope.
You missed where attribute
string login = "SELECT ID, Username, [Password] FROM Employee where Username=#? and [Password]= #? ";
I have a code written that automatically adds and reads information from my SQL Server 2012 Express table, Logins. But it wont work, here is the code:
private void Form1_Load(object sender, EventArgs e)
{
SqlConnection myConnection = new SqlConnection("user id=myComputer;" + "server=MYCOMPUTER-PC\\SQLEXPRESS;" +
"Trusted_Connection=yes;" + "database=loginTest; " + "connection timeout=5");
try
{
myConnection.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
SqlCommand myCommand = new SqlCommand("INSERT INTO dbo.Logins Values ('John','Password','Admin')", myConnection);
try
{
SqlDataReader myReader = null;
SqlCommand myCommand1 = new SqlCommand("select * from Logins",
myConnection);
myReader = myCommand1.ExecuteReader();
while (myReader.Read())
{
MessageBox.Show(myReader["Column1"].ToString());
MessageBox.Show(myReader["Column2"].ToString());
}
}
catch (Exception ex1)
{
MessageBox.Show(ex1.ToString());
}
}
I have debugged the program and it all seems to go through fine, it skips over :
{
MessageBox.Show(myReader["Column1"].ToString());
MessageBox.Show(myReader["Column2"].ToString());
}
for some reason, and it doesnt write the values i told it to.
Can anyone tell me why? Im a beginner at SQL, so go easy please :)
PS It doesnt fire out any error codes or exceptions
You Logins table doesn't have any records, if you mean you want to try inserting some record first to test, it's this line causing your problem:
SqlCommand myCommand = new SqlCommand("INSERT INTO dbo.Logins Values ('John','Password','Admin')", myConnection);
myCommand.ExecuteNonQuery();//Do this to insert something into your Logins first.
it skips over [...]
Presumably that's because there's no data to read, so myReader.Read() just returns false.
it doesnt write the values i told it to.
You don't actually tell it to write anything. You create a SqlCommand to insert data, but you never execute it. You need to use myCommand.ExecuteNonQuery. You should also use using statements for the commands, the connection and the reader, to make sure they get closed properly.