I am building a win form application in c# which will be installed on windows server 2008. All users that will be using this application connects with their username and password using remote desktop connection. What happens if two or more users opens this application? Will it work correctly for all user? or it become race condition ( who gets first wins? :) ) what do I need to do to make it work correctly for all users? maybe I need to create System.Net.Sockets or something else?
UPDATED:
Code to select data from table and then update it:
DuomenysDataSet ds; //dataset which was created when I create a database on visual studio
public static string ID { get; set; }
private void FillDataGrid()
{
try
{
SqlCommand command = new SqlCommand("SELECT PirminiaiNuo,PirminiaiIki,Ikainis,MenesinisMokestis,Metine FROM \"" + ID + "\"", DBConnection);
ds = database.FillData(command, "Ikainiai"); // "Ikainiai" = DataSet table name
IkainiaiView.Columns[0].DataPropertyName = "PirminiaiNuo";
IkainiaiView.Columns[1].DataPropertyName = "PirminiaiIki";
IkainiaiView.Columns[2].DataPropertyName = "Ikainis";
IkainiaiView.Columns[3].DataPropertyName = "MenesinisMokestis";
IkainiaiView.Columns[4].DataPropertyName = "Metine";
IkainiaiView.Enabled = false;
IkainiaiView.DataSource = ds.Tables[a];
IkainiaiView.Enabled = true;
}
To update table I pass same SqlCommand and table name to the database class method updateTable code below:
public void updateDatabase(SqlCommand command, string tableName)
{
sql = new SqlDataAdapter(command);
sql.SelectCommand = command;
sql.SelectCommand.Connection = Connection();
SqlCommandBuilder c = new SqlCommandBuilder(sql); // not sure if this is necessary
sql.Update(ds.Tables[tableName]);
}
Code to create a new table: here ID is the AutoIncrement id from different table (primary key) this is why it is not a parameter.
public static string ID { get; set; }
private void Kainininkas_Load(object sender, EventArgs e)
{
SqlCommand command = new SqlCommand("SELECT * INTO \"" + ID + "\" FROM IkainiuSablonasPilnas", DBConnection);
try
{
DBConnection.Open();
command.ExecuteNonQuery();
DBConnection.Close();
}
catch (Exception ex)
{
TopMostMessageBox.Show(ex.Message);
}
}
To insert new rows to the table i use this code:
DBConnection = database.Connection();
SqlCommand command = new SqlCommand("INSERT INTO Imones (Imone,Adresas,ImonesKodas,PVMKodas,Vykdytojas,Musu,SutartiesNr,SutartiesData,Sutartis,Active,Buhalteris) VALUES (#Imone,#adresas,#ImonesKodas,#PVMKodas,#Vykdytojas,'',#SutartiesNR, #SutartiesData,#Sutartis,#Active,#Buhalteris);", DBConnection);
command.Parameters.AddWithValue("#Imone", textBox1.Text);
command.Parameters.AddWithValue("#adresas", textBox2.Text);
command.Parameters.AddWithValue("#ImonesKodas", UzsakovasImonesKodasText.Text);
command.Parameters.AddWithValue("#PVMKodas", textBox4.Text);
command.Parameters.AddWithValue("#Vykdytojas", ImoniuSarasasCmb.Text);
command.Parameters.AddWithValue("#SutartiesNR", textBox3.Text);
command.Parameters.AddWithValue("#SutartiesData", dateTimePicker1.Text);
command.Parameters.Add("#Sutartis", SqlDbType.Binary).Value = buff;
command.Parameters.AddWithValue("#Active", aktyvi);
command.Parameters.AddWithValue("#Buhalteris", comboBox1.Text);
command.ExecuteNonQuery();
As long as the app isn;t locking physical resources (files) while another copy tries to use them, you can open/use multiple copies of your winforms app at the same time.
EDIT
As an extra note, thanks to CodeCaster, if you implement a file based db access routine, that may lock the file when accessing the DB file, you could run into issues. If you use a service level DB implementation, like SQL Express, then there should not be any issues with running multiple copies of the app.
As a last note, its perfectly normal for an application to run as multiple copies on the same Application server. Think about, Ms Word, Exel, Outlook, Adobe Reader, Windows Explorer...
Just make sure you take the above points into account.
Related
string query = "SELECT * FROM staff";
string mySQLConnectionString = "datasource=127.0.0.1;port=3306;username=root;password=;database=workshopdb;sslmode=none";
MySqlConnection databaseConnection = new
MySqlConnection(mySQLConnectionString);
MySqlCommand commandDatabase = new MySqlCommand(query, databaseConnection);
databaseConnection.Open();
MySqlDataReader myReader = commandDatabase.ExecuteReader();
if (myReader.HasRows) //checks whether the table is empty
{
while (myReader.Read()) //reads rows consequently
{
MessageBox.Show(myReader.GetString(0) + " " + myReader.GetString(1) + " " + myReader.GetString(3));
//get strings(x) are columns of the table in the db
}
}
databaseConnection.Close();
}
I used this code but It doesn't recognize the username and password that I entered. Instead of recognizing the entered user it shows all users in the database.
In C#, building platform is .NET. Most of the time we can use MSSQL for DB activities. To Configure we can use MSSQL Server Express. XAMPP runs on Apache server. But for the .NET development we need IIS server. At your end arise conflicts. Do more research abourt what are you doing and get know about the dependent technologies
I'm having problems with updating a row in the Users table of my Access DB. Here is the code below:
private void SaveProfileInfo()
{
try
{
ChangeForeColorOfStatusMsg(Color.Black);
ChangeTextOfStatusMsg("Saving new profile information...");
const string cmd = #"UPDATE Users SET LastName=#LastName,FirstName=#FirstName,MiddleName=#MiddleName,Add_Num=#Add_Num,Add_Street=#Add_Street,Add_Brgy=#Add_Brgy,Add_City=#Add_City,MobileNumber=#MobileNumber,Gender=#Gender WHERE ID=#ID;";
var dbConn = new OleDbConnection(cs);
var dbCmd = new OleDbCommand(cmd, dbConn);
dbCmd.Parameters.AddWithValue("#ID", UserLoggedIn.ID);
dbCmd.Parameters.AddWithValue("#LastName", txtLastName.Text);
dbCmd.Parameters.AddWithValue("#FirstName", txtFirstName.Text);
dbCmd.Parameters.AddWithValue("#MiddleName", txtMiddleName.Text);
dbCmd.Parameters.AddWithValue("#Add_Num", txtUnitNum.Text);
dbCmd.Parameters.AddWithValue("#Add_Street", txtStreet.Text);
dbCmd.Parameters.AddWithValue("#Add_Brgy", GetBrgySelectedItem());
dbCmd.Parameters.AddWithValue("#Add_City", GetCitySelectedItem());
dbCmd.Parameters.AddWithValue("#MobileNumber", txtMobileNumber.Text);
dbCmd.Parameters.AddWithValue("#Gender", GetGenderSelectedItem());
dbConn.Open();
dbCmd.ExecuteNonQuery();
dbConn.Close();
ChangeForeColorOfStatusMsg(Color.MediumSeaGreen);
ChangeTextOfStatusMsg("All changes have been saved! This window will close itself after two seconds.");
Thread.Sleep(2000);
CloseForm();
}
catch (Exception)
{
ChangeForeColorOfStatusMsg(Color.Crimson);
ChangeTextOfStatusMsg("Something went wrong while we were connecting to our database. Please try again later.");
hasFinishedEditting = false;
}
}
This method will be done on a separate thread, when the user updates his profile information.
UserLoggedIn is actually a field of a User class (a class that defines a row in my table), which stores all the info of the user who's currently logged in.
When I run this, it does not produce any exceptions or errors. But when I check my table, the values are not updated.
I copy-pasted these codes from the registration form (which works) that I made with this system, and modified it into an UPDATE cmd than an INSERT cmd.
I also made Change Username and Password Forms that use the same cmd as shown below:
public void ChangePass()
{
try
{
ChangeForeColorOfMsg(Color.Silver);
ChangeTextOfMsg("Changing password...");
const string cmd = "update Users set Pass=#Pass where ID=#ID";
var dbConn = new OleDbConnection(cs);
var dbCmd = new OleDbCommand(cmd, dbConn);
dbCmd.Parameters.AddWithValue("#Pass", txtNewPass.Text);
dbCmd.Parameters.AddWithValue("#ID", UserLoggedIn.ID);
dbConn.Open();
dbCmd.ExecuteNonQuery();
dbConn.Close();
ChangeTextOfMsg("Password successfully changed!");
}
catch (Exception)
{
ChangeForeColorOfMsg(Color.Silver);
ChangeTextOfMsg("A problem occurred. Please try again later.");
}
}
And these codes work for me. So I'm really confused right now as to why this update cmd for the profile information isn't working... Is there something I'm not seeing here?
OleDb cannot recognize parameters by their name. It follows a strictly positional order when sending them to your database for updates. In your code above the first parameter is the #ID but this parameter is used last in your query. Thus everything is messed up.
You just need to move the add of the #ID parameter as last in the collection
As a side note, you should be very careful with AddWithValue. It is an handy shortcut, but it has a dark side that could result in wrong queries.
Take a look at
Can we stop using AddWithValue already?
I am trying to rebuild an application that originally used sqlite to now use 'localdb'. (I want an application that can create its own database locally and at runtime without requiring a pre-installed instance of sql server or sql express on the target machine)
I want to move away from using a 'third party' library (sqlite) as experience has told me it can be a pain to get it working from scratch, and towards something supposedly more straightforward to get up and running from scratch.
Using code copied (and slightly modified) from the web I have managed to create an mdf file dynamically/programmatically, but I am puzzled by what happens if I run it more than once, even if I choose a new filename each time. Namely it seems to somehow keep the changes/additions made on each run. Below is the relevant code...
public partial class Form1 : Form
{
SqlConnection conn;
public void CreateSqlDatabase(string filename)
{
string databaseName =
System.IO.Path.GetFileNameWithoutExtension(filename);
conn = new SqlConnection(
String.Format(
#"Data Source=(LocalDB)\v11.0;Initial Catalog=master;Integrated Security=True"
));
conn.Open();
using (var command = conn.CreateCommand())
{
command.CommandText =
String.Format(
"CREATE DATABASE {0} ON PRIMARY (NAME={0}, FILENAME='{1}')"
, databaseName, filename);
command.ExecuteNonQuery();
command.CommandText =
String.Format("EXEC sp_detach_db '{0}', 'true'", databaseName);
command.ExecuteNonQuery();
}
conn.Close();
}
private void button1_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
CreateSqlDatabase(openFileDialog1.FileName);
}
}
private void button2_Click(object sender, EventArgs e)
{
conn.Open();
SqlCommand comm = conn.CreateCommand();
comm.CommandText =
"create table mytable (id int, name nvarchar(100))";
comm.ExecuteNonQuery();
comm.CommandText =
"insert into mytable (id,name) values (10,'testing')";
comm.ExecuteNonQuery();
comm.CommandText = "select * from mytable";
SqlDataReader reader = comm.ExecuteReader();
while (reader.Read())
{
textBox1.Text +=
reader["id"].ToString() + ", " + reader["name"].ToString() + "\r\n";
}
conn.Close();
}
}
If I run the app once It runs through fine.
If I run the app a second time, and choose a different filename for the database it tells me 'mytable' already exists.
If I comment out the create table code it runs, but the select query returns multiple rows indicating multiple inserts (one for each time the app runs)
I am just seeking to understand why this happens. Do I need to delete database/table each time if I want the app to behave as if it has created the database/table from scratch on each subsequent run?
You have initial catalog 'master' in your connection string. Are you sure you haven't created the tables in the master database instead of the newly created database?
After the creation & detach of the database file, you could try and change your connection to:
SqlConnection con = new SqlConnection(#"Data Source=(LocalDB)\v11.0;Integrated Security=True;AttachDbFilename=c:\xxx\xxx\xxx.mdf");
I am currently writing a small application to keep track of monetary ins and outs, something just to improve my general C# skills. For my Login Screen currently I have the following Code
private void Login_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'spendingInsAndOutsDataSet.Users' table. You can move, or remove it, as needed.
this.usersTableAdapter.Fill(this.spendingInsAndOutsDataSet.Users);
}
private void button1_Click(object sender, EventArgs e)
{
string userNameText = userName.Text;
string passwordText = password.Text;
foreach (DataRow row in spendingInsAndOutsDataSet.Users)
{
if (row.ItemArray[4].Equals(userNameText) && row.ItemArray[5].Equals(passwordText))
{
MessageBox.Show("Login Successful");
MainGUI newForm = new MainGUI();
this.Visible = false;
newForm.Show();
break;
}
else
{
userName.Text = String.Empty;
password.Text = String.Empty;
MessageBox.Show("Login Failed");
break;
}
}
}
What I am looking to do when the Login is Sucessful is to write the MachineName of the current PC to a field in Users table in my SQL Database. That way when I come to start creating records I can quickly find my UsersId (which is a foreign key in my Transactions table).
I know you can get the Active Machine Name using the System.Enviroments path but Im unsure exactly how to go about writing the update. I know how to do it using a SqlCommand but I am wondering if there is a simpler way using the DataRows I have used within the ForEach loop.
Thanks in advance, any questions let me know.
James
Assuming it is an Access database (If not then make the necessary changes):
Use an Adapter to fill a table with your results. Then compare the row columns with the information provided by the user. Don't forget to use parameters to avoid injections that may potentially ruin your database or expose your user's information to a hacker.
DataTable dt = new DataTable();
String sql = "SELECT * FROM users WHERE user = #user and password=#password"
OleDbConnection connection = getAccessConnection();
OleDbDataAdapter da = new OleDbDataAdapter(sql, connection);
da.SelectCommand.Parameters.Add("#user", OleDbType.VarChar).Value = userNameText;
da.SelectCommand.Parameters.Add("#password", OleDbType.VarChar).Value = password.Text;
try
{
connection.Open();
da.Fill(dt);
connection.Close();
}
catch(OleDbException ex)
{
connection.Close();
MessageBox.Show(ex.ToString());
}
if(dt.Rows.Count == 1)
return true; //username && password matches
else if(dt.Rows.Count == 0)
return false; // does not match
You could also use AddWithValue for your parameters.
da.SelectCommand.Parameters.AddWithValue("#user", userNameText);
getAccessConnection() is a predefined OleDbConnection function that has the connection to the database setup and creates a new instance of the connection for you (that I have created for myself).
public OleDbConnection getAccessConnection()
{
this.connection = new OleDbConnection();
this.connection.ConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source="
+ Classified.SOURCE + ";Jet OLEDB:Database Password="
+ Classified.PASS + ";";
return this.connection;
}
It is preferred to create classes for all of these functions for developers who may join in on the project. Also read up on C# test driven development as well.
Also it looks like your loop will break even if that one record fails, only allowing it to go to it's first record.
Onto creating your own data set and filling it with queried tables is also useful. Here is a brief example:
DataSet ds = new DataSet();
ds.Tables.Add(dt, "userSearchedTable");
ds.Tables["userSearchedTable"].Rows[0][1].ToString();
Then you can declare a specific data table within the set when ever you need to.
In your foreach loop, set the MachineName of the current PC on relevant row then at the end of the method call:
this.usersTableAdapter.Update(this.spendingInsAndOutsDataSet.Users);
This will update the database with the machine name
However looking at your code there are a few additional comments to make I'd like to add to improve what you have:
You are loading the entire data table and then checking it for the username and password. Really you query for the user ID in the database, load that single row and check the password. If you have many users, your current implementation will create a lot of network traffic.
Instead of:
foreach (DataRow row in spendingInsAndOutsDataSet.Users)
Consider using something like:
foreach (SpendingInsAndOutsDataSet.UsersRow row in spendingInsAndOutsDataSet.Users)
i.e. the strongly typed version of the data row object. This means you can use:
row.Username.Equals(userNameText)
instead of
row.ItemArray[4].Equals(userNameText)
Also if you are anticipating that this will be used over a network, you should look to encrypt the passwords.
I'm new to C# and have a background in SQL so apologies if this is a very stupid query, but I have been trawling google for about 2 hours now and can't find what I need. If someone knows of an article they can point me to, that would be great.
I have a simple windows forms application, and I'm setting up a login box so that users have to enter their user ID to proceed.
I have a SQL Server DB (SQL 2005) with the following table:
Users
UserID (int); userName nvarchar(50)
I am using Visual Studio 2010
What I'm stymied by is how to check whether their userID exists in my SQL Table (called users...) I'm not going to put any code here because it's been rewritten from scratch so many times that a clean slate is probably best!
Ideally, I want the user to enter their user ID, and click 'login'. When they do this, if their userID is not valid in the DB table then I need it to give an error msgBox; if it is valid then it should log them in, passing their userID and userName (stored in the DB table) to a variable which I can use elsewhere in the application to populate fields.
I hope this makes sense, and I'm sure I've missed the perfect article out there which will explain it all - hopefully one of you kind people can point me in the right direction!
Thank you
You should make a simple SQL query with the userID the user entered, like
SELECT UserID from Users where userID= value. The executeNonQuery() will return the number of matches. If the returned value ==1, means that the userid exists in the database. If the returned value is different from 1, means that the userid not exists or it was registered multiple times. So, if is 1 then you cand call a different form to make different things, else you call anoter form or output a messagebox with an error message
/*table code
* create table login
(
id varchar(25),
pass varchar(25)
)
*
*
*
*
*/
string Connectstring = #"Data Source=DELL-PC;Initial Catalog=stud;Integrated Security=True";
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
SqlConnection cn = new SqlConnection(Connectstring);
cn.Open();
SqlCommand cmd = new SqlCommand("select * from log where id=#a and pass=#b", cn);
cmd.Parameters.AddWithValue("#a", textBox1.Text.ToString().ToUpper());
cmd.Parameters.AddWithValue("#b", textBox2.Text);
SqlDataReader dr = cmd.ExecuteReader();
if ((dr.Read() == true))
{
MessageBox.Show("The user is valid!");
Form2 mainForm = new Form2();
mainForm.Show();
this.Hide();
}
else
{
MessageBox.Show("Invalid username or password!");
}
}
Declare a connection string to Your database
string connString = #"Data Source=.\SQLEXPRESS;Initial Catalog=YourDatabase;Integrated Security=True";
After this You can use a validate method below
private bool ValidateUserById(string connString, int id)
{
using (var conn = new SqlConnection(connString))
{
conn.Open();
var sqlString = string.Format("Select * From Users where Id = {0}", id);
using (var cmd = new SqlCommand(sqlString, conn))
{
return cmd.ExecuteScalar() != null;
}
}
}
Then on button click You can check the user
if (ValidateUserById(connString, Convert.ToInt32(textBox1.Text)))
{
//..
}
else
{
//..
}