Hi having abit of a problem with my code it refuses to do my else statement have a global variable set to say attempts = 3
runs the while loop but when i put an invalid pin it basically just doesnt run anything i would appreciate any help possible thanks
while (read.Read())
{
if (read.HasRows)
{
}
//If the card isnt confiscated then do this:
if (((Boolean)(read["confiscated"]) == false))
{
string cardnum = read["cardNumber"].ToString();
string pinnum = read["PIN"].ToString();
//Compare the results in the table against those put in by the customer
if (string.Equals(cardnum, cardBox.Text) && string.Equals(pinnum, pinNumber.Text))
{
MessageBox.Show("Welcome customer");
MessageBox.Show("Card Number " + cardnum + " PIN " + pinnum);
//if the login details match and everything is correct then bring the next form up
MessageBox.Show("Details are correct");
pinNumber.Clear();
//open the options form
Form optionForm = new optionForm();
optionForm.Show();
//hide this form
this.Hide();
break;
}
else
{
if (attempts == 1)
{
sqlCommandATM.Parameters["#cardNum"].Value = cardBox.Text;
sqlCommandATM.Parameters["#confiscated"].Value = true;
MessageBox.Show("Your card has been confiscated please contact The bank of Glamorgan to resolve the issue");
pinNumber.Clear();
}
EDIT
I've tried to understand what you're doing. I assume you're trying to authenticate a person by credit card number and PIN against a database, and you're doing it by getting all the entries from a database table and looping over them to find the one that matches the user input. You want to allow the user to do that three times before locking the credit card.
I see more than one issue with that: The task of finding the correct row in the table for the user should be left to the database. This is much quicker and less error prone. So if you'd like to do it right, then you should have an SQL statement like:
int attempts = 0;
bool success = false;
while (!success && attempts < 3)
{
using (SQLCommand exists = new SQLCommand("SELECT ID FROM ... WHERE CCardNo = #cardNo AND PIN = #pin", conn))
{
exists.Parameters.AddWithValue("#cardNo", cardNum);
exists.Parameters.AddWithValue("#PIN", pinnum);
object idObject = (int)exists.ExecuteScalar();
if (idObject == null || idObject == DBNull.Value)
{
attemps++;
}
else
{
success = true;
}
if (attempts >= 3)
{
// Lock out the user
}
}
}
if (success)
{
...
}
If you really insist on doing it your way, then please make sure that attempts is initialized properly and is incremented on each login attempt - in your current code, you'd increment it on every row you're validating against, so you'd lock out every customer who's not within the first three rows you're getting from the database.
Original reply
OK, you're reading all data from a DataReader in a while loop:
while (read.Read())
{
Then what do the following three lines do? You wouldn't be here if read.HasRows was false, because read.Read() would have returned false already. The following three lines are pointless and can be removed, leaving only what's inside the block.
if (read.HasRows)
{
}
The usual way would be:
if (read.HasRows)
{
while (read.Read())
{
...
}
}
More is hard to tell as you're not showing us the complete code - what value does attempts have before the while loop, for example?
Ignoring the syntax errors in your posted code, my first guess is that your attempts variable is not set to 1 when control goes inside the else statement so, based on your posted code, nothing should happen. Could you show us where this attempts variable is declared/changed?
From the code supplied you have not incremented attempts on each attempt the user trys to enter a pin. where teh code is;
string pinnum = read["PIN"].ToString();
attempts++;
Something like that. Its hard to tell what you have in total as its obviously snipped code.
You said the global attempts = 3.
If that's the case, you should check if the failed attempts is >= 3.
if (string.Equals(cardnum, cardBox.Text) && string.Equals(pinnum, pinNumber.Text))
{
// Load account
}
else if (attempts >= 3)
{
// Confiscate card
}
else
{
attempts ++;
}
Related
In my web app the admin can assign a web page to a specific user, therefore that user can only access that specific page.
So to give an idea of how this works:
in my database I have a table with the web pages in, Webpage1.aspx, Webpage2.aspx etc.
The admin can create an user assign Webpage1.aspx to that user
Then when that user logs in they can only see the link to their page (all other links are hidden)
This is now the problem I have:
This works on a DataTable row number so when adding a new web form it re-arranges the DataTable row numbers which then when the user logs in again they can see all other links cause the table numbers have changed.
So to give a visual idea:
if (Session["Privilege"] != null)
{
DataTable dtPrivilege = (DataTable)Session["Privilege"];
/* Dashboard */
if (bool.Parse(dtPrivilege.Rows[1]["Read"].ToString()) == false && dtPrivilege.Rows[1]["FormName"].ToString() == "dashboard.aspx")
lnkDashboard.Visible = false;
/* Settings */
if (bool.Parse(dtPrivilege.Rows[2]["Read"].ToString()) == false && dtPrivilege.Rows[2]["FormName"].ToString() == "general.aspx")
lnkSettings.Visible = false;
/* Web Pages */
if (bool.Parse(dtPrivilege.Rows[0]["Read"].ToString()) == false)
lnkWebpages.Visible = false;
else
{
if (bool.Parse(dtPrivilege.Rows[0]["Read"].ToString()) == false && dtPrivilege.Rows[0]["FormName"].ToString() == "Webpage1.aspx")
lnkWebpage1.Visible = false;
}
So it reads by row number so when you add another page it messes up the row number and the 1st users saved in the database then gets the wrong link assigned to their privilege, because it moved the row number to 1 or 2 depending on how many web forms have been added.
So my question is, how can I make it so that it reads the string instead of the row number? So for example
if (Session["Privilege"] != null)
{
DataTable dtPrivilege = (DataTable)Session["Privilege"];
/* Web Pages */
if (bool.Parse(dtPrivilege.Rows[0]["Read"].ToString()) == false)
lnkWebpages.Visible = false;
else
{
if (bool.Parse(dtPrivilege.Rows[**Webpage1.aspx**]["Read"].ToString()) == false && dtPrivilege.Rows[0]["FormName"].ToString() == "Webpage1.aspx")
lnkWebpage1.Visible = false;
}
Is this possible and if so how can I achieve my goal?
Please let me know if you need more info or I haven't explained properly :-)
Thanks
You can use Linq to achieve this.
Add using System.Linq; at the top of your .cs page.
Then add below line to generate IEnumerable(Array) of all rows inside dtPrivilege DataTable,
DataRow[] allRows = dtPrivilege.Select();
And finally, add if blocks like below for all your webpages.
if (allRows.Any(x => x["FormName"].ToString() == "Webpage1.aspx" &&
x["Read"].ToString().ToLower() == "false"))
{
lnkWebpage1.Visible = false;
}
What above if block says:
It checks if there exists Any row in allRows, which has FormName = "Webpage1.aspx" and Read = "false". And if it exist, just set lnkWebpage1.Visible = false
I am going through a YouTube video, to learn ASP.NET. I've gotten it to work for the most part, with a somewhat major caveat: I can't retrieve a value from a hidden field ID. Because of that, I don't have a value to send to a stored procedure to create or update.
The commented out line is the original statement. When I have that then execute
.ExecuteNonQuery, I get the following error:
Procedure or function 'ResourceCreateOrUpdate' expects parameter '#ResourceID', which was not supplied
When I try to display hfResourceID, I have nothing when trying to pass 0, for a create, or the ResourceID value, i.e. 1. That value however, doesn't get there. I know the stored procedure works because I can execute it in SQL Server Management.
I tried moving hfResourceID to a string, then a integer value, but I seem to be having problems creating the if/else: everything is marked as an error. When I hover over the lines, I get the following message, which pretty much leave me clueless:
"Embedded statement cannot be a declaration or labeled statement".
Would I be able to get any pointers on how to clear up my error, please? Thanks.
2017-10-13 # 10:38: code updated
<asp:HiddenField ID="hfResourceID" runat="server" />
protected void btnSave_Click(object sender, EventArgs e)
{
int intResourceID = 0;
bool boolIDHasValue = true;
try
{
intResourceID = Convert.ToInt32(hfResourceID.Value);
}
catch (Exception ex)
{
lblErrorMessage.Text = ex.Message;
boolIDHasValue = false;
}
if (boolIDHasValue)
{
if (sqlconnODRConnection.State == System.Data.ConnectionState.Closed)
sqlconnODRConnection.Open();
SqlCommand sqlcmdCreateOrUpdate = new SqlCommand("ResourceCreateOrUpdate", sqlconnODRConnection);
sqlcmdCreateOrUpdate.Parameters.AddWithValue("#ResourceID", intResourceID);
sqlcmdCreateOrUpdate.Parameters.AddWithValue("#Status", txtStatus.Text.Trim());
sqlcmdCreateOrUpdate.Parameters.AddWithValue("#FirstName", txtFirstName.Text.Trim());
sqlcmdCreateOrUpdate.Parameters.AddWithValue("#MiddleName", txtMiddleName.Text.Trim());
sqlcmdCreateOrUpdate.Parameters.AddWithValue("#LastName", txtLastName.Text.Trim());
sqlcmdCreateOrUpdate.Parameters.AddWithValue("#NickName", txtNickName.Text.Trim());
sqlcmdCreateOrUpdate.Parameters.AddWithValue("#Gender", txtGender.Text.Trim());
sqlcmdCreateOrUpdate.Parameters.AddWithValue("#USCitizen", txtUSCitizen.Text.Trim());
sqlcmdCreateOrUpdate.ExecuteNonQuery();
sqlconnODRConnection.Close();
string strResourceID = hfResourceID.Value;
Clear();
if (strResourceID == "")
lblSuccessMessage.Text = "Saved Successfully";
else
lblSuccessMessage.Text = "Updated Successfully";
FillGridView();
}
}
There are a few issues with the code you copied from that video. But here a snippet as to how it should be done. I've added 3 ways to convert from the HiddenField value to an actual int. Which one you use can depend on how you want to handle errors, 0 values etc. Not included in the snippet, but I like to check for IsNullOrEmpty while using Trim(), that gets rid of spaces that might make the value non-convertible if (!string.IsNullOrEmpty(hfResourceID.Value.Trim())).
int intResourceID = 0;
//this will try to convert but you won't see exeptions when failed
Int32.TryParse(hfResourceID.Value, out intResourceID);
//checks if there is a value in the hiddenfield, but throws yellow screen if not convertible
if (!string.IsNullOrEmpty(hfResourceID.Value))
{
intResourceID = Convert.ToInt32(hfResourceID.Value);
}
//catch an error when the value is not convertible, can be wrapped with !string.IsNullOrEmpty(hfResourceID.Value)
try
{
intResourceID = Convert.ToInt32(hfResourceID.Value);
}
catch (Exception ex)
{
//handle the error, can be seen with ex.Message
}
//if the hidden value is still 0 (for whatever reason) you might not want to execute the query
//so the next part will return and stop executing the rest of the code
if (intResourceID == 0)
{
return;
}
//update the database, using 'using' will ensure proper closure of the connection and disposing of any objects
using (SqlConnection connection = new SqlConnection("myConnectionString"))
using (SqlCommand command = new SqlCommand("ResourceCreateOrUpdate", connection))
{
//set the command type and add the parameters
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#ResourceID", SqlDbType.Int).Value = intResourceID;
try
{
//open the database connection and execute the command
connection.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
//there was an error opening the database connection or with the command, can be viewed with ex.Message
}
}
Your error regarding the embedded statement is because you a declaring
if (strResourceID == "")
int intResourceID = 0;
else
int intResourceID = (Convert.ToInt32(hfResourceID.Value));
When decalring a variable directly after an If or else then you need your curly brackets. So...
if (strResourceID == "")
{
int intResourceID = 0;
}
else
{
int intResourceID = (Convert.ToInt32(hfResourceID.Value));
}
As for your other issues I would need to see your client side code.
Take a look on ASP code, specifically the way you are setting hidden field value. I guess it is properly marked as runat=server but maybe some problem is going on in your asp.net code, try to debug client code by using: console.log function and see the output in your console browser.
I'm a beginner programmer and I'm writing a C# application that makes a query to a database. However I am wondering how could I check that an ID exists (ID is entered by user in the console application) and if it doesn't, display a message.
Here's my code:
Console.WriteLine("enter ID");
try
{
var province_id = Convert.ToInt32(Console.ReadLine());
var aquery2 = from test in context.BusinessEntityAddress
where test.Address.StateProvinceID == province_id
group test.BusinessEntity.Person.LastName by new { test.BusinessEntityID, test.BusinessEntity.Person.LastName, test.BusinessEntity.Person.FirstName }
into balk
select new {
...
};
Didn't paste the whole code but this is the part my question is about. At the line
where test.Address.StateProvinceID == userid
I would like to check if that ID exist in the database, and if it doesn't, display a message. I don't know how to do that.
Note that all the code is already in a try{}catch{} because I also need to ensure that the user input is an integer.
Thank you
It seems like you're trying to do a lot more then just search for a user ID in your question? You seem to be saying StateProvinceId is a user Id? In which case a simple test like this should suffice:
if (!context.Addresses.Any(a => a.StateProvinceID == userid))
{
Console.WriteLine("User doesn't exist");
}
Although, it would seem more logical to look in a users table. EG, context.Users. Which would hence question why you are doing a group by (which shouldn't be needed).
You will need to add each data object to your context, but if you could elaborate more on what exactly isn't working, we can help more.
You don't need to run the code inside a try for that, instead first you have to check for the existence of the user:
int number;
//check if the userId is an integer
if(!int.TryParse(userId, out number)){
Console.WriteLine("Please enter a valid interger!!");
return;
}
var beAddress = context.BusinessEntityAddress;
//check for the userId exist in the DB
var flag = beAddress.Any(a => a.Address.StateProvinceID == number);
if(flag){
//do something if the user exist
}
else{
//do something else if the user doesn't exist
}
For checking if the string is a valid integer you should use int.TryParse("8", NumberStyles.Integer, System.Globalization.NumberFormatInfo.InvariantInfo, out number);, this way you are not just checking if the string is a number but if is an integer.
You shouldn't use try-catch for a classic user error, like number parsing. int.TryParse() is made for this :
// get rid of the try-catch, you wont need it anymore
int userid;
var input = Console.ReadLine();
if (!int.TryParse(input, out userID))
{
Console.WriteLine("Invalid input : '{0}' is not a number", input);
return;
}
var aquery2 = from test in context.BusinessEntityAddress
where test.Address.StateProvinceID == userid
group test.BusinessEntity.Person.LastName by new { test.BusinessEntityID, test.BusinessEntity.Person.LastName, test.BusinessEntity.Person.FirstName } into balk
select new
{
/* ... */
};
if (!aquery2.Any())
{
// not found... display a message
}
else
{
// found... do stuffs
}
This is the code which I'm using. I don't know about console application but know little bit about C# and SQL. I'm not sure I understood clearly but just hope this might help you. Thank you.
bool idfound; (declare in the field of a Class)
private void buttonIDcheck_Click(object sender, RoutedEventArgs e)
(a Event which has to be created by Visual Studio, not manually)
{
SqlConnection Conn = new SqlConnection();
Conn.ConnectionString = yourConnectionString;
Conn.Open();
SqlCommand check_idexistcomm = new SqlCommand();
check_idexistcomm.Connection = Conn;
check_idexistcomm.CommandText = "SELECT id FROM yourtable";
var check_idexistda = new SqlDataAdapter(check_idexistcomm);
SqlDataReader check_idexistreader = check_idexistcomm.ExecuteReader();
while (check_idexistreader.Read())
{
if (check_idexistreader["id"].ToString()== text value inputed by user here)
{
idfound = true;
break;
}
}
check_idexistreader.Close();
Conn.Close();
if (idfound=true)
{
your code here to accept the user as authorized
}
else
{
MessageBox.Show("Sorry, you're not authorized");
}
}
I have a method that queries a table for the count of its records. QA has discovered an "edge case" where if a particular operation is canceled in a particular order and speed (as fast as possible), the GUI "forgets" about the rest of the records in that table (the contents of the tables are uploaded to a server; when each one finishes, the corresponding table is deleted).
To be clear, this table that is having records deleted from it and then queried for count ("workTables") is a table of table names, that are deleted after they are processed.
What I have determined (I'm pretty sure) is that this anomaly occurs when a record from the "workTables" table is in the process of being deleted when the workTables table is queried for the count of its records. This causes an exception, which causes the method to return -1, which in our case indicates we should cuase the GUI to not display those records.
Is there a way to check if a table is in the process of having a record deleted from it, and wait until after that operation has completed, before proceeding with the query, so that it won't throw an exception?
For those interested in the specifics, this method is the one that, under those peculiar circumstances, throws an exception:
public int isValidTable(string tableName)
{
int validTable = -1;
string tblQuery = "SELECT COUNT(*) FROM ";
tblQuery += tableName;
openConnectionIfPossibleAndNecessary();
try
{
SqlCeCommand cmd = objCon.CreateCommand();
cmd.CommandText = tblQuery;
object objcnt = cmd.ExecuteScalar();
validTable = Int32.Parse(objcnt.ToString());
}
catch (Exception ex)
{
validTable = -1;
}
return validTable;
}
...and this is the method that deletes a record from the "workTables" table after the corresponding table has had its contents uploaded:
private void DropTablesAndDeleteFromTables(string recordType, string fileName)
{
try
{
WorkFiles wrkFile = new WorkFiles();
int tableOK = 0;
DataSet workfiles;
tableOK = wrkFile.isValidWorkTable(); // -1 == "has no records"
if (tableOK > 0) //Table has at least one record
{
workfiles = wrkFile.getAllRecords();
//Go thru dataset and find filename to clean up after
foreach (DataRow row in workfiles.Tables[0].Rows)
{
. . .
dynSQL = string.Format("DELETE FROM workTables WHERE filetype = '{0}' and Name = '{1}'", tmpType, tmpStr);
dbconn = DBConnection.GetInstance();
dbconn.DBCommand(dynSQL, false);
populateListBoxWithWorkTableData();
return;
} // foreach (DataRow row in workfiles.Tables[0].Rows)
}
}
catch (Exception ex)
{
SSCS.ExceptionHandler(ex, "frmCentral.DropTablesAndDeleteFromTables");
}
}
// method called by DropTablesAndDeleteFromTables() above
public int isValidWorkTable() //reverted to old way to accommodate old version of DBConnection
{
// Pass the buck
return dbconn.isValidTable("workTables");
}
I know this code is very funky and klunky and kludgy; refactoring it to make more sense and be more easily understood is a long and ongoing process.
UPDATE
I'm not able to test this code:
lock (this)
{
// drop the table
}
...yet, because the handheld is no longer allowing me to copy files to it (I get, "Cannot copy [filename.[dll,exe] The device has either stopped responding or has been disconnected" (it is connected, as shown by ActiveStync))
If that doesn't work, I might have to try this:
// global var
bool InDropTablesMethod;
// before querying that database from elsewhere:
while (InDropTablesMethod)
{
Pause(500);
}
UPDATE 2
I've finally been able to test my lock code (copies of binaries were present in memory, not allowing me to overwrite them; the StartUp folder had a *.lnk to the .exe, so every time I started the handheld, it tried to run the buggy versions of the .exe), but it doesn't work - I still get the same conflict/contention.
UPDATE 3
What seems to work, as kludgy as it may be, is:
public class CCRUtils
{
public static bool InDropTablesMethod;
. . .
if (CCRUtils.InDropTablesMethod) return;
CCRUtils.InDropTablesMethod = true;
. . . // do it all; can you believe somebody from El Cerrito has never heard of CCR?
CCRUtils.InDropTableMethod = false;
UPDATE 4
Wrote too soon - the bug is back. I added this MessageBox.Show(), and do indeed see the text "proof of code re-entrancy" at run-time.
while (HHSUtils.InDropTablesMethod)
{
MessageBox.Show("proof of code re-entrancy");
i++;
if (i > 1000000) return;
}
try
{
HHSUtils.InDropTablesMethod = true;
. . .
}
HHSUtils.InDropTablesMethod = false;
...so my guess that code re-entrancy may be a problem is correct...
I know what is causing the Redirect loop in my code, I am just not sure how to fix it. First, my code.
switch (Request.QueryString["Error_ID"])
{
case "1":
// Error Code 1 is when a user attempts to access the Admin section and does not have rights to.
MultiView1.ActiveViewIndex = 1;
break;
case "2":
// Error Code 2 is when a user is not currently Active.
MultiView1.ActiveViewIndex = 2;
break;
default:
// Default is View Index 0 for default access.
MultiView1.ActiveViewIndex = 0;
break;
}
// Get current username.
string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
// Test to see if user is Active.
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["HSEProjRegConnectionString1"].ConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("SELECT [active] FROM [tbl_Person] WHERE username LIKE #username", conn))
{
cmd.Parameters.AddWithValue("#username", "%" + userName + "%");
var res = cmd.ExecuteScalar();
bool registeredAndActive = (bool)res;
if (registeredAndActive)
{
// Active Condition. The DEFAULT in SWITCH() will take care of displaying content.
}
else
{
// !Active Condition. Shows an alternative version of the default page where the user is told they do not have access.
Response.Redirect("default.aspx?Error_ID=2");
}
}
The point of the code is to first check for a Query String in the SWITCH() method in case one is provided on a later page. Then it grabs current AD username logged in with, and then checks a user database to see if the user is marked Active. If so, it does nothing as it will allow the page to load as normal. If not, then it redirects to the same page but appends an Error_ID so that I can display a different View saying that the user does not have access. I am pretty sure this is where the redirect loop is coming from. Does anyone have any ideas on how I can eliminate Redirect Loop? I tried doing a Request.Url.ToString() and then a !var.Contains to do the Redirect, but I couldn't make that work either.
EDIT: I should note that I am interested to hear if anyone has any alternatives to Response.Redirect(). It works, but originally, I was using Response.End() and that didn't allow any code to run so came up with using Response.Redirect() and a QueryString to do what I wanted.
You are testing if your user is active twice. Also, in the second check, you keep redirecting the page to itself, which keeps doing the checks.
Your first check is here:
switch (Request.QueryString["Error_ID"])
{
(...)
case "2":
// Error Code 2 is when a user is not currently Active.
MultiView1.ActiveViewIndex = 2;
break;
(...)
and your second check is here:
if (registeredAndActive)
{
// Active Condition. The DEFAULT in SWITCH() will take care of displaying content.
}
else
{
// !Active Condition. Shows an alternative version of the default page where the user is told they do not have acces.
Response.Redirect("default.aspx?Error_ID=2");
}
So the second check redirects the page to itself, and it keeps looping forever.
The easiest way to fix this, IMHO, is to not check if your current user is active if your error code is "2", i.e. you could either:
1) Stop the page execution if Error_ID is 2, i.e. change the first check to:
case "2":
// Error Code 2 is when a user is not currently Active.
MultiView1.ActiveViewIndex = 2;
Response.End(); // <--- this will stop the execution before reaching the first block
break;
2) Don't redirect the page again, if Error_ID is 2, i.e. change your second check to:
if (registeredAndActive)
{
// Active Condition. The DEFAULT in SWITCH() will take care of displaying content.
}
else
{
// !Active Condition. Shows an alternative version of the default page where the user is told they do not have acces.
if (MultiView1.ActiveViewIndex != 2) { // check if the page has already been redirected
Response.Redirect("default.aspx?Error_ID=2");
}
}
IMHO, solution 2 seems to be the cleanest and most elegant of the two
You only need to perform the database check if the query string value (Error_ID) is not 1 or 2. The way the logic is written, you will always check for whether or not the user is active and if they are not, then it will keep sending the Error_ID=2 query string value to the page and you will be stuck in a loop. I would recommend separating out the logic to test for the query string into a separate method and have it return a Boolean of whether or not to attempt to query the database for the Active value.
How about doing something like this:
if(MultiView1.ActiveViewIndex != 2)
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["HSEProjRegConnectionString1"].ConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("SELECT [active] FROM [tbl_Person] WHERE username LIKE #username", conn))
{
cmd.Parameters.AddWithValue("#username", "%" + userName + "%");
var res = cmd.ExecuteScalar();
bool registeredAndActive = (bool)res;
if (registeredAndActive)
{
// Active Condition. The DEFAULT in SWITCH() will take care of displaying content.
}
else
{
// !Active Condition. Shows an alternative version of the default page where the user is told they do not have acces.
Response.Redirect("default.aspx?Error_ID=2");
}
}
}
}