Why would this code display error even when it shouldn't? - c#

I am sort of new to programming and I cannot get this simple looking code to work
What I am trying to do is make a login system that works on an array so its easier to edit and add new people onto the list.
string[] UserCodes = { "admin", "testcode" }; //these are the arrays
string[] UserWords = { "123", "testword" };
public void Button_Clicked(object sender, EventArgs e)
{
for (int i = 0; i < UserCodes.Length; i++)
if (UserCode.Text.Equals(UserCodes[i]) && UserWord.Text.Equals(UserWords[i]))
{
Navigation.PushAsync(new HomePage());
}
for (int i = 0; i < UserCodes.Length; i++)
if (UserCode.Text != (UserCodes[i]) || UserWord.Text !=(UserWords[i]))
{
DisplayAlert("Something Went Wrong", "Incorrect Password or Username", "Try Again");
}
} // And this is the "main" code
I believe the main problem arises from the second part, where it displays an error, because if I don't enter the password correctly it works as it should but if I do enter correctly It sends me to the home page while still displaying the error. I have tried using else if, and i tried to use (!command.Equals(Array[i])). I am extremely confused as to why its acting this way.

Step through this code in the debugger. If you type in a correct UserCode and UserWord you will call Navigation.PushAsync(new HomePage())... and then keep going.
You next check if any UserWord or UserCode is not what you typed, and it will be, then show your error message.
You probably want to call return after Navigation.PushAsync(new HomePage()), or skip over the second for statement.

It feels like a code smell to me when you have one loop checking for a condition followed by an entirely different loop for when that condition fails. As #Corvus noted, you should return once you've made a match, and then you defer the error message after all looping is complete:
public void Button_Clicked(object sender, EventArgs e)
{
for (int i = 0; i < UserCodes.Length; i++)
{
if (UserCode.Text.Equals(UserCodes[i]) && UserWord.Text.Equals(UserWords[i]))
{
Navigation.PushAsync(new HomePage());
return; // thanks to #Corvus
}
}
DisplayAlert("Something Went Wrong", "Incorrect Password or Username", "Try Again");
}
That said, there are improvements you could make but did not ask about. Usually, the user name is acceptable regardless of case, but the password always must match the case. You are okay on the treatment of passwords but the user name match could be changed to ignore case.
Also, you have two arrays that must be in-sync with each other. I would suggest instead a Dictionary<string, string> where the user name is the Key and password is the Value.

Related

I messed up a "While" loop... Can i fix it?

I tryed to make a while loop, and i know the problem, i just have no idea how to fix it. The int I use just never updates, making the code useless... I use Visual Studio, windows fom app, if that changes something... Sorry for the lenght, but i don't know where's the problem. (Input 1 and 2 are textboxes...) The text file I use looks like this:
Username: new line
(costum text) new line
Password: new line
(costum text) new line
Username: new line
...
Here's the code:
public partial class Form1 : Form
{
//This is part of the problem
int search = 0;
//This is part of the problem (end)
public void OK_Click(object sender, EventArgs e)
{
string path = #"filePath.txt";
var count = File.ReadLines(path).Count();
string user = File.ReadLines(path).Skip(search + 1).Take(1).First();
string pass = File.ReadLines(path).Skip(search + 3).Take(1).First();
//Main problem
if (Input1.Text != "" && Input2.Text != "")
{
while (Input1.Text == user && Input2.Text == pass)
{
if (search < count)
{
search = search + 4;
}
}
if (search < count)
{
MessageBox.Show("worked");
search = 0;
}
}
//Main problem (end)
}
}
This can be greatly simplified. The usernames and passwords are on alternating lines, so they need to be declared inside of the loop. You can also use a for loop to control skipping to the next username/password combination at the end of each iteration of the loop. And you don't need to do File.ReadLines multiple times, that causes it to hit the disk multiple times for something you could just hold in memory once.
You should also rename your textboxes to have names that represent the data they should contain. So UsernameTextbox instead of Input1 for example.
public void OK_Click(object sender, EventArgs e)
{
string path = #"filePath.txt";
var fileLines = File.ReadLines(path);
var authenticatedSuccessfully = false;
for (int line = 0; line < fileLines.Length - 1; line += 2)
{
var user = fileLines[line];
var password = fileLines[line + 1];
if (UsernameTextbox.Text == user && PasswordTextBox.Text == pass)
{
authenticatedSuccessfully = true;
break;
}
}
if (authenticatedSuccessfully)
{
MessageBox.Show("You are logged in!");
}
else
{
MessageBox.Show("Incorrect username or password!");
}
}
Of course...you should keep in mind that this is not secure at all. In the real world, passwords should be one way hashed and salted. Then when a user wants to authenticate you hash the password again and compare it to the stored value. If they match, then they provided the correct password. Storing passwords in plaintext is not a good idea.
Your while condition is wrong. You can use for loop for that(using counters), or you need to rebuild your while loop. You must put if conditions inside While loop dont make them separate. https://www.w3schools.com/cs/cs_while_loop.asp. Using while loop is good chance to go for infinite. So I am using For loops all the times.

errorprovider or message box?

I have a simplr windows form input(student name,studentid) to display to a listbox.
I need to check for duplicate student id in listbox before i add a value.
Can I use error provider on student id text box to do this?
any help much appreciated
please check last bit of my code below -is for/foreach loop required?
Thanks
private void txtSid_Validating(object sender, CancelEventArgs e)
{
bool can = false;
int sid = 0;
if (string.IsNullOrEmpty(txtSid.Text))
{
ep1.SetError(txtSid, "Please Enter Student ID");
can = true;
}
else if (!int.TryParse(txtSid.Text, out sid))
{
ep1.SetError(txtSid, "Student ID must be a number");
can = true;
}
else
for (int i = 0; i < lstDisplay.Items.Count; i++)
{
if (lstDisplay.Items[i].ToString().Contains(txtSid.Text))
{
ep1.SetError(txtSid, "Student ID already added");
can = true;
}
{
}
e.Cancel = can;
}
Yes, you can use Error Provider. In fact, for in-place validation such as you are doing, I tend to prefer them. I try to limit pop-up boxes, as they can be annoying to the user. Error providers, coupled with disabling a Save button, for instance, can provide a block to continuing as well as information as to why, all without annoying pop-ups.
As for checking against items already in the list box, yes, I would loop over them checking one at a time. If there are a lot of them, or if performance is highly critical, then you could implement a custom comparer for the items you add to the list box. They could also be of a custom class to facilitate the mechanics of it all.

how to save an ID if the you leave the name empty?

I'm Working in this program for two days and i can not find out where I'm doing Wrong.If you could help me I really appreciate it .The Problem is when I enter 11111 for my the curator ID and leave the name Box Empty,it is not suppose to saved the curator ID .After if I put something in the box and i enter 11111 for the Curator ID it says "ID already exist please try again".
private void SaveCuratorBtn_Click(object sender, RoutedEventArgs e)
{
curator Curator = new curator();
try
{
Curator.ID = CuratorIDbox.Text;
bool sameid = false;
for (int i = 0; i < curatorlist.Count; i++)
{
if (curatorlist[i].ID == Curator.ID)
{
sameid = true;
break;
}
}
if (sameid)
MessageBox.Show("ID already exist please try again !");
else
{
curatorlist.add(Curator);
}
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
try
{
bool checkingname = false;
Curator.NAME = CuratorNamebox.Text;
checkingname = true;
if (checkingname)
{
MessageBox.Show("Curator Saved");
}
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
if (sameid)
{
MessageBox.Show("ID already exist please try again !");
}
else
{
curatorlist.add(Curator);
}
This code block is doing the following:
If the ID already exists, show an error (good!)
If the ID doesn't exist, add the whole Curator to curatorlist.
What you need is another step of validation in your code to make sure that box the name textbox and the ID textbox contain information. You could achieve this like so (replace the names of course):
else
{
if(string.IsNullOrEmpty(NameTextbox.Text) || string.IsNullOrEmpty(IdTextbox.Text)
{
MessageBox.Show("Uh oh!")
} else {
curatorlist.add(Curator);
}
Here you're checking if the textboxes are empty before even thinking about adding the Curator to curatorlist. If you need to make other checks (such as no numbers [1,2,3,4] in your NameTextbox), there are multiple ways of doing so.
You say that "when I enter 11111 for my the curator ID and leave the name Box Empty,it is not suppose to saved the curator ID"; but there is nothing in the sample code that you have provided which prevents this. That might be what you want; but you haven't coded it that way: the "curatorlist.add(Curator);" will add the curator to the collection regardless of what is in the Name box.
P.S. consider using a Dictionary, as the lookup will be faster.

Prevent other Methods from running under a condition is met in a previous Method

My problem is when the user clicks on myButton the program operates perfectly fine. But if the user was to input a value less than 3 in the first textbox a message box will appear to the user stating that the value must be greater than 3 metres. If you click OK the next method in myButton runs anyway and the result message box appears anyway.
I've tried looking around to solve this problem of mine using Nested For Loops but failed to get them to work (most likely a fault on my end). I also prefer not to use Goto because it isn't exactly good programming practice to use. Of course you can tell me otherwise if you want :) .
// Button
private void myButton_Click(object sender, EventArgs e)
{
checkIfNumericalValue();
testIfTextBoxOnesMinimumIsMet();
testIfTextBoxTwosMinimumIsMet();
displayResultToUser();
resetOrClose();
}
// Textbox One
public void testIfTextBoxOnesMinimumIsMet()
{
if (length < 3)
{
MessageBox.Show("length must be greater than 3 metres");
}
}
Help would be greatly appreciated this is also my second attempt at C# on Visual Studio 2012. Do not worry this has nothing to do with my year 10 schooling as my school doesn't have a programming subject. This problem occurs in testIfTextBoxOnesMinimumIsMet() and testIfTextBoxOnesMinimumIsMet() as well but if someone can help me with this one method I should be able to fix the rest :)
You could throw an exception from your inner functions and catch it from your button's function, something like this:
// Button
private void myButton_Click(object sender, EventArgs e)
{
try
{
checkIfNumericalValue();
testIfTextBoxOnesMinimumIsMet();
testIfTextBoxTwosMinimumIsMet();
displayResultToUser();
resetOrClose();
}
catch (ArgumentException ex)
{
// The error message we defined at the exception we threw
MessageBox.Show(ex.Message);
}
}
// Textbox One
public void testIfTextBoxOnesMinimumIsMet()
{
if (length < 3)
{
throw new ArgumentException("Length must be greater than 3 meters.");
}
}
An alternative would be to deal with the validation within your button like so:
// Button
private void myButton_Click(object sender, EventArgs e)
{
checkIfNumericalValue();
if (length < 3)
{
MessageBox.Show("Length must be greater than 3 meters.");
return;
}
testIfTextBoxTwosMinimumIsMet();
displayResultToUser();
resetOrClose();
}
What happens above is that the return will leave that function without further processing anything else.
So, if I'm understanding this correctly, if the text boxes contain numerical values, text box 1 meets the minimum and text box 2 meets the minimum, you want to displayResultToUser() and then resetOrClose().
If that's the case, you can have the 3 methods checkIfNumericalValue(), testIfTextBoxOnesMinimumIsMet() and testIfTextBoxTwosMinimumIsMet() return a bool depending on what the minimum condition is and then write something like this:
private void myButton_Click(object sender, EventArgs e)
{
if (checkIfNumericalValue() && testIfTextBoxOnesMinimumIsMet(Convert.ToInt32(txtBoxOne.Text)) && testIfTextBoxTwosMinimumIsMet(Convert.ToInt32(txtBoxTwo.Text)))
{
displayResultToUser();
resetOrClose();
}
}
public bool testIfTextBoxOnesMinimumIsMet(int length)
{
if (length < 3)
{
MessageBox.Show("length must be greater than 3 metres");
return false;
}
return true;
}
It appears that you need some other variable to track whether or not you have encountered errors. To do this, you could have a bool noErrors variable defined, and you should return a boolean from your error check methods that is True if there were no errors, otherwise False. This way you know if you ran into any problems.
Finally, you should check for the state of errrorsFound before running any of your other methods.
For example:
// Button
private void myButton_Click(object sender, EventArgs e)
{
bool noErrors =
isNumericalValue() &&
textBoxOnesMinimumIsMet() &&
textBoxTwosMinimumIsMet();
if (noErrors)
{
displayResultToUser();
resetOrClose(); // I'm not sure if this should happen regardless of errors?
}
}
// Textbox One
public bool textBoxOnesMinimumIsMet()
{
if (length < 3)
{
MessageBox.Show("length must be greater than 3 metres");
return false;
}
return true;
}

Why with some browsers i get a wrong value for my Session object?

I am coding an asian language learning module for my mojoportal-based iphone-optimized website (work in progress, english resources are not fully translated: http://ilearn.dandandin.it/kanatrainer.aspx)
It's a simple "guess how to read this" game, with the right answer stored in a Session object.
I don't understand why, but, expecially using Safari, users will get someone else's Session value
This is an excerpt from the code (i removed some stuff, translated the variables)
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
...
generateRandom();
}
}
protected void generateRandom()
{
int i, j = 0, livello = 5, chance = 0;
System.Random acaso = new Random();
...
while (j <= 0)
{
j = acaso.Next((Convert.ToInt32(TextBoxlunghezza.Text) + 1));
}
...
for (int k = 0; k < j; k++)
{
i = acaso.Next(livello);
Session["randomLetters"] += (globals.asianCharacters[i]);
...
}
...
}
protected void AnswerButton_Click(object sender, EventArgs e)
{
string compare = Server.HtmlEncode(InputTextBox.Text.ToLower());
if (compare == "")
{
Label1.Text = ("You did not write anything");
return;
}
if (Session["randomLetters"].ToString() != compare)
{
Label1.Text = ("Wrong!" + Session["randomLetters"]);
}
else
{
Label1.Text = ("Right!" + Session["randomLetters"]);
}
...
}
What happens in visual studio, with every browser:
randomLetters is "hello". User writes "hello" in the textbox, and "hello" is compared to "hello". Label says "Right! hello".
What happens in iis, only in webkit-based browsers:
randomLetters is "hello". User writes "hello" in the textbox, but "hello" is compared to "goodbye". Label says "Wrong! goodbye".
I don't understand how Session["randomLetters"] has changed
Public vs private code:
How are your storing the session state? Cookie? Database? so on... I have had many problems (usually with IE 8) with the way that the browser was caching the pages and the cookies. Usually, changing the respective setting in the browser fixed the problem. I don't know if that helps here. To make it more robust, I then have to find a way to notify the user when one of these settings is not right.
Using HiddenFields i "solved" the problem (but i don't like that way)

Categories

Resources