local variable might be not initialized before accessing c# - c#

So i try to get around this issue. I know for a fact that this will be initialized before am calling it but c# can not know this i guess.
I cannot do xUser user = new xUser;
One work around i was thinking about was using an List and store the values in list and then create the xuser after the while loop but it seems very messy. And i really wanna learn how to avoid this kind of errors.
noUSer iuser = new noUSer();
xUser user;
string sql = "select * from accounts where id='" +id +"'";
SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection);
SQLiteDataReader reader = command.ExecuteReader();
while (reader.Read())
{
iuser.user_name = reader["login"].ToString();
iuser.password = reader["password"].ToString();
iuser.cookie_file = #"c:\cookies";
user = iusers.create(iguser);
}
m_dbConnection.Close();
if (tab_mode.SelectedTab.Text == "User")
{
dothiscall(user); //Error on "user" local variable might be not initialized before accessing
}

You should initialize the variable to null, however, be aware that if the code inside while loop doesn't execute, it will remain null.

Yes better way is create a list iusers and add new iuser inside while loop. and your whileloop to user you are adding iguser which can not find. It should be iuser
xUser user = new xUser();
string sql = "select * from accounts where id='" +id +"'";
SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection);
SQLiteDataReader reader = command.ExecuteReader();
while (reader.Read())
{
noUSer iuser = new noUSer();
iuser.user_name = reader["login"].ToString();
iuser.password = reader["password"].ToString();
iuser.cookie_file = #"c:\cookies";
user = iusers.Add(iuser);
}

When you do:
xUser user;
You are merely creating a pointer.meaning if u had an object of type xUser later on and wanted a pointer to it you could do for example something like :
user =(xUser)DataGridView1.Rows[0].cells[myxUserObjectInCell.index].Value;
That way making changes to user will make changes to the object in your grid.
However if you're planning on creating an object of type xUser,then you need to do:
xUser user = new xUser();
The new keyword makes it initialize.

Related

Saving SQLite query results as variables

So basically I'm looking to try to make a basic login for a WPF app and store certain user data into variables with C#. Problem I'm running into is separating the result of different datatypes into variables to use later in the app. Something similar to the GET command in PHP. I have seen some documentation about creating a separate class replicating the data you need and could probably run individual queries for each variable, but that just feels wrong and I know there's a better way.
Here is my code so far:
Database databaseObject = new Database();
var userid = LoginTextBox.Text;
string query = "SELECT * FROM users WHERE userid = #userid";
SQLiteCommand myCommand = new SQLiteCommand(query, databaseObject.myConnection);
databaseObject.OpenConnection();
myCommand.Parameters.AddWithValue("#userid", userid);
SQLiteDataReader result = myCommand.ExecuteReader();
if (result.HasRows)
{
/* GET RESULT INTO VARIABLES */
}
else
{
LoginTextBox.Text = "";
}
databaseObject.CloseConection();
Don't think I'm too off here just need a push in the right direction :)
You can create a User class that has all the properties coming back from the table.
Something like:
public class User {
public int UserId { get; set }
public string UserName { get; set; }
}
And then just read the properties from your SQLiteDataReader and assign them to the properties of the class:
var user = new User();
user.UserId = (int)result["userid"];
user.UserName = (string)result["username"];

How to prevent SQL Injection in this code?

How can i prevent these code of getting SQL injected? It's a login system that i'm learning. Here's the code!
if (!(string.IsNullOrWhiteSpace(textBox1.Text)) && !(string.IsNullOrWhiteSpace(textBox2.Text)))
{
MySqlConnection mcon = new MySqlConnection("datasource = 127.0.0.1; port = 3306; username = root; password = ; database = rpgmaster;");
mcon.Open();
DataTable table = new DataTable();
MySqlDataAdapter adapter = new MySqlDataAdapter("Select * From users where Username = '" + textBox2.Text + "' and password = '" + textBox1.Text + "'", mcon);
adapter.Fill(table);
if (table.Rows.Count <= 0)
{
MessageBox.Show("Você não está registrado!");
}
else
{
MessageBox.Show("Logado com sucesso! ");
}
mcon.Close();
}
Thanks for the help! Really appreciate it!
If you're learning, you could perhaps move on from this old low level way of doing data access and use something a bit more modern and easy. Dapper is an example of a library that isn't a huge leap above what you already know but makes your life a lot nicer:
using(var conn = new MySqlConnection("conn str here"){
var sql = "SELECT count(*) FROM tblUsers WHERE username = #u AND password = #p";
var prm = new {
u = txtUsername.Text, //give your textboxes better names than textbox2,textbox1!
p = txtPassword.Text.GetHashCode() //do NOT store plain text passwords!
};
bool valid = await conn.QuerySingleAsync<int>(sql, prm) > 0;
if(valid)
... valid login code
else
... invalid login
}
Some notes on this:
dapper is a device that you simply give your sql and parameter values to
the sql holds #parameters names like #u
an anonymous typed object has properties called the same name as the parameter name, with a value, like u = "my username"
use async/await when running queries; dapper makes this easy. Avoid jamming your UI up on queries that take 10 seconds to run
in this case you only need to ask the db to count the matching records, you don't need to download them all to find out if there are any, so we use QuerySingleAsync<int> which queries a single value of type it, and if it's more than 0, the login was valid
never store password in a database in plaintext. Use a one way hashing function like MD5, SHA256 etc, even the lowly string.GetHashCode is better than storing plaintext, particularly because people use the same passwords all the time so anyone breaking into your db (very easy; the password is in the code) will reveal passwords treat people probably use in their banking etc. We can't really be asking, on the one hand, how to prevent a huge security hole like SQL injection, and then on the other hand leave a huge security hole like plaintext passwords ;)
always name your textboxes a better name than the default textboxX - it takes seconds and makes your code understandable. If Microsoft called all their class property names like that, then the entire framework would be full of things like myString.Int1 rather than myString.Length and it would be completely unusable
life is too short to spend it writing AddWithValue statements; use Dapper, Entity Framework, strongly typed datasets.. Some db management technology that eases the burden of writing that code
Where Dapper makes things really nice for you is its ability to turn objects into queries and vice versa; this above is just a basic count example, but suppose you had a User class:
class User
{
string Name { get; set; }
string HashedPassword { get; set; }
int age {get; set; }
}
And you had a table tblUsers that was similar (column names the same as the property names), then you could query like:
User u = new User() { Name = "someuser" };
User t = await conn.QuerySingleAsync<User>("SELECT Name, HashedPassword, Age FROM tblUsers WHERE Name = #Name", u);
We want to look up all the info of the someuser user, so we make a new User with that Name set (we could also use anonymous type, like the previous example) and nothing else, and we pass that as the parameters argument. Dapper will see the query contains #Name, pull the contents of the Name from the u user that we passed in, and run the query. When the results return it will create a User instance for us, fully populated with all the data from the query
To do this old way we'd have to:
have a command,
have a connection,
add parameters and values,
open the connection,
run the sql,
get a reader,
check if the reader had rows,
loop over the reader pulling the first row,
make a new User,
use reader.GetInt/GetString etc to pull the column values out one by one and
finally return the new user
oh and dispose of all the db stuff, close the connection etc
Writing that code is repetitive, and it is really boring. In computing, when we have something repetitive and boring, that we need to do thousands of times through out life (like serializing to json, calling a webservice, designing a windows UI) we find some way to make the computer do the repetitive boring bit; they do it faster and more accurately than we can. This is exactly what Dapper does; it does away with that boring repetitive and reduces it to a single line where you say what you want back, using what query, with what parameters. And it keeps your UI working:
await x.QueryAsync<type>(query, parameters)
Win. Seek out some Dapper tutorials! (I have no affiliation)
Try using parameters please see updated sample of your code below:
if (!(string.IsNullOrWhiteSpace(textBox1.Text)) && !(string.IsNullOrWhiteSpace(textBox2.Text)))
{
using (MySqlConnection mcon = new MySqlConnection("datasource = 127.0.0.1; port = 3306; username = root; password = ; database = rpgmaster;"))
{
mcon.Open();
MySqlCommand cmd = new MySqlCommand("Select * from users where username=?username and password=?password", mcon);
cmd.Parameters.Add(new MySqlParameter("username", textBox2.Text));
cmd.Parameters.Add(new MySqlParameter("password", textBox1.Text));
MySqlDataReader dr = cmd.ExecuteReader();
if (dr.HasRows == true)
{
MessageBox.Show("Você não está registrado!");
}
else
{
MessageBox.Show("Logado com sucesso! ");
}
}
}
Use parameters to pass and check their length, Use stored procedure instead of a query in the code. Use columns instead of * in Select. And please make sure you don't store the plain password in the DB
Use Parameters
using (MySqlConnection mcon = new MySqlConnection(connectionString))
{
string commandText = "SELECT * FROM users WHERE Username = '#tbxText'"
SqlCommand command = new SqlCommand(commandText, mcon);
command.Parameters.AddWithValue("#tbxText", textBox2.Text);
}

How to load query Result to a IList<T>

I have a IList<T>
IList<Student> studsList = new IList<Student>();
How to load name and age properties from this query to my studsList?
using(OracleCommand command = new OracleCommand(querySQL, connection))
{
connection.Open();
string query = "SELECT name, age FROM Student";
using(OracleCommand command = new OracleCommand(querySQL, connection)) {
using(OracleDataAdapter oracleDataAdapter = new OracleDataAdapter()) {
oracleDataAdapter.SelectCommand = command;
command.ExecuteNonQuery();
//What to do here?
}
}
If you command.ExecuteNonQuery();, you are saying "I don't expect results". If you want to see the results, you'll need to use ExecuteReader, which returns an IDataReader API that allows you to loop over the rows in a forwards direction using .Read(). Then, per row you have access to a range of APIs for accessing columns, including via the indexer ([]), or GetValue or GetValues or typed access methods (GetString, GetInt32, etc).
Or more simply - use a tool like dapper!
var students = connection.Query<Student>(query);
this deals with:
connection lifetime (opening, etc)
creating the command
parameterization (not shown in this example, but really easy)
executing the command
processing the reader
parsing the contents of each row into the T (Student in this case)
closing everything down correctly
For a parameterized example:
var region = "North";
var students = connection.Query<Student>(
"select * from Students where Region=#region", new { region });
(you might need to use $region or :region depending on your ADO.NET provider)

How can I use TableDirect for SQL Server CE?

I have code that works for querying data from a SQL Server CE table and populating a generic list with it. That can be seen here:
But a comment there indicates I should trade in my horse-and-buggy for a Leer Jet; so, I'm trying to adapt code I found here and have this so far:
public static List<HHSUtils.InventoryItem> SelectLocalInventoryItemsTableDirect()
{
var invItems = new List<HHSUtils.InventoryItem>();
using (var conn = new SqlCeConnection(dataSource))
{
conn.Open();
SqlCeCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.TableDirect;
cmd.CommandText = "InventoryItems";
using (SqlCeResultSet rs cmd.ExecuteResultSet(ResultSetOptions.Scrollable))
{
cmd.Prepare();
while (rs.Read())
{
var invItem = new HHSUtils.InventoryItem
{
Id = Convert.ToString(rs["Id"]),
PackSize = Convert.ToInt16(rs["PackSize"]),
Description = Convert.ToString(rs["Description"]),
DeptDotSubdept = Convert.ToDouble(rs["DeptDotSubdept"]),
Unit_Cost = Convert.ToDouble(rs["UnitCost"]),
Unit_List = Convert.ToDouble(rs["UnitList"]),
UPC_code = Convert.ToString(rs["UPCCode"]),
UPC_pack_size = Convert.ToInt16(rs["UPCPackSize"]),
CRV_Id = Convert.ToInt32(rs["CRVId"])
};
invItems.Add(invItem);
}
}
}
return invItems;
}
...but since I'm simply looping through the result set to populate the generic list, I reckon I don't want ResultSetOptions.Updatable (and I'll need different code following that). Of the following possibilities:
Insensitive
None
Scrollable
Sensitive
Updatable
...which is best for my situation - Scrollable?
UPDATE
This seems to work fine, and fast, but I still don't know which ResultSetOptions property is optimal...This msdn article talks about this enumeration, but doesn't exactly go into great depth about when they should/not be used.
You'd want to use None in your case. cmd.Prepare is also unnecessary. As indicated in this question, GetValues is also faster.

Store the results in memory (List) using c#

I want to store many record that I query from database in list , one record has 10 fields, in order to loop it later.
But I have no idea to do that. Anyone can answer me please.
Below is a good practice to store data and loop through among them.
Create Model/POCO class as:
public class DataClassName
{
public int Id { get; set; }
public string Name { get; set; }
//Create properties according to your fields
}
Fill and get data list:
public List<DataClassName> GetDataList()
{
List<DataClassName> dataList = new List<DataClassName>();
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "select * from TargetTableName";
cmd.CommandType = CommandType.Text;
try
{
using (SqlConnection connection =
new SqlConnection("YourConnectionString"))
{
cmd.Connection = connection;
connection.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
dataList.Add(
new DataClassName()
{
Id = Convert.ToInt32(reader["ID"]),
Name = Convert.ToString(reader["Name"])
//Set all property according to your fields
});
}
}
}
}
catch(Exception ex_)
{
//Handle exception
}
return dataList;
}
Save data that is returned from GetDataList() into your datalist and loop through among the data as required.
Here's how you'd go about storing it in a DataTable:
SqlConnection conn = new SqlConnection("yourConnectionStringHere");
SqlCommand GetData = new SqlCommand();
GetData.Connection = conn;
GetData.CommandText = "select * from yourTable"; // or whatever your query is, whether ad hoc or stored proc
// add parameters here if your query needs it
SqlDataAdapter sda = new SqlDataAdapter(GetData);
DataTable YourData = new DataTable();
try
{
sda.Fill(YourData);
}
catch
{
sda.Dispose();
conn.Dispose();
}
If you have 10 fields, you'd be hard-pressed to store your data in a List<T> object. Your best bet would be to create a class tailored to the data you are looking to retrieve (if you want to take it a step further than the DataTable implementation above) with corresponding properties/fields.
Perhaps you could give a bit more information...
If you use the entity framework or similar to query the database, it will probably return an enumerable object.. you just need to call .ToList() on this to save it as a list.
Do you mean that you want to store this across web requests? Then you could store it in the HttpRuntime.Cache collection, allowing for it to expire after some time.
Alternatively store it in a static property. Session is also an option but it doesn't sound like the best option for this

Categories

Resources