Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I decided to make a list with acounts in it. With a foreach I can automatically check all acounts instead of alot of elseif's. Directly below the foreach I want to check wether what is in the textboxes is equal with the acounts, if this is the case a new Form opens up.
Acount a = new Acount("Admin", "123");
Acount b = new Acount("Admin2", "321");
List<Acount> acounts = new List<Acount>();
acounts.Add(a);
foreach(Acount acount in acounts)
{
if (txtUsername.Text == ???)
{
openForm();
}
else
{
MessageBox.Show("Invalid password or username.");
}
}
Here the Acount class:
class Acount
{
public string Name{ get; set; }
public string Password{ get; set; }
public Acount()
{
}
public Acount(string name, string password)
{
this.Name= name;
this.Password= password;
}
}
I think what your are looking for is something like this:
if (txtUsername.Text == acount.Name && txtPassword.Text == acount.Password)
So if both username and password are correct for any account, you'll end up opening the new form.
Be careful however, the way your loop is currently written, even if the user enters valid credentials for one user in your list, you'll still open the MessageBox on each loop except the one that's good.
I'd suggest either using .Any as suggested by someone else, or using a boolean value to keep track of the matching status as such:
bool isFound = false;
foreach (Account account in accounts)
{
if (txtUsername.Text == account.Name && txtPassword.Text == account.Text)
{
isFound = true; // we found a match
break; // no need to keep searching, we can break
}
}
if (isFound)
openForm();
else
MessageBox.Show("...");
Instead of for loops you can just use the method Any.
Also there is a bug in your code that it would open many forms if there are multiple matches (because the for loop is not broken after finding one).
So, here is a quick solution to the code:
// NOTE: REMOVE THE FOR LOOP as it's not needed anymore.
// Just use the code below instead of the loop.
if (acounts.Any(account => txtUsername.Text == account.Name && account.txtPassword == account.Password)) {
openForm();
} else {
MessageBox.Show("Invalid password or username.");
}
Also don't forget to add the following using statements if you haven't:
using System.Collections.Generic;
using System.Linq;
Create an extension for handling decision call.
public static class Extensions
{
public static void ReactWith(this Acount acct, Action succes, Action failure)
{
Action actionToPerform = acct != null ? succes : failure;
actionToPerform.Invoke();
}
}
In main file call the extension as below.
private void OpenForm()
{
// launch form code here.
}
private void ErrorMesage()
{
// Message box code here.
}
List<Acount> acounts = new List<Acount>();
var validAcct = acounts.Where(a => a.Name == "abc").FirstOrDefault();
validAcct.ReactWith(OpenForm, ErrorMesage);
Related
I'm trying to make it so when the given answer is neither 1 nor 2 the message "Please enter a valid answer." shows up and it goes back to the question.
Here's my code:
Coloration(ConsoleColor.DarkMagenta, "What do you want to do? [1/2]");
Console.WriteLine("1. Draw");
Console.WriteLine("2. Stay");
int i = 0;
string input1 = Console.ReadLine();
// If answer is not 2, go through this, if answer is 2 continue
if (input1 != "2")
{
// If answer is 1 add 1 to i
if (input1 == "1")
{
i++;
}
// If answer is neither 1 nor 2; go back to question
if (input1 != "1" || input1 != "2")
{
Coloration(ConsoleColor.Red, "Please enter a valid answer.");
}
}
You want something more like this...
Console.WriteLine("What do you want to do? [1/2]");
Console.WriteLine("1. Draw");
Console.WriteLine("2. Stay");
int userChoice = 0;
bool validInput = false;
while (!validInput)
{
Console.WriteLine();
Console.WriteLine("Enter choice [1/2]...");
string input = Console.ReadLine();
string trimmedInput = input.Trim();
if (trimmedInput == "1" || trimmedInput == "2")
{
validInput = true;
userChoice = Int32.Parse(trimmedInput);
}
}
// We leave the while loop here once validInput == true
// Now take action based on userChoice
Console.WriteLine("You chose " + userChoice);
Console.ReadLine();
As others have noted, you need to keep watching user input. You have your answer but I wanted to also introduce you to the concept of a Read Eval Print Loop (AKA a REPL). Your current solution is not going to scale well. Take a look at the following implementation of your desired UI:
using System;
using System.Collections.Generic;
namespace MyProgram
{
class Program
{
// Don't actually use inner classes. This is just for demonstration purposes.
class Command
{
public Command(string description, Action action)
{
this.Description = description;
this.Action = action;
}
public string Description { get; private set; }
public Action Action { get; private set; }
}
static void Main(string[] args)
{
// Create a dictionary of commands, mapped to the input that evokes each command.
var availableCommands = new Dictionary<string, Command>();
// Note that since we are storing the descriptions / commands in one place, it makes
// changing a description or adding/modifying a command trivial. Want "Draw" to be invoked
// by "d" instead of "1"? Change it here and you're done.
availableCommands.Add("1", new Command("Draw", Draw));
availableCommands.Add("2", new Command("Stay", Stay));
// This command demonstrates how to use a lambda as an action if you so desire.
availableCommands.Add("3", new Command("Exit", () => System.Environment.Exit(1)));
// Build command list string
var cmdList = string.Join('/', availableCommands.Keys);
// Display welcome message
Coloration(ConsoleColor.DarkMagenta, $"What do you want to do? [{cmdList}]");
// Show user initial list of commands
DisplayAvailableCommands(availableCommands);
// Read Eval Print Loop (REPL).
while (true)
{
var userInput = Console.ReadLine();
// If the user entered a valid command, execute it.
if (availableCommands.ContainsKey(userInput))
{
availableCommands[userInput].Action();
// If you want the user to be able to perform additional actions after their initial successful
// action, don't return here.
return;
}
// Otherwise, let them know they didn't enter a valid command and show them a list of commands
else
{
Coloration(ConsoleColor.Red, "Please enter a valid answer.");
DisplayAvailableCommands(availableCommands);
}
}
}
// I'm just assuming your coloration method looks something like this...
static void Coloration(ConsoleColor color, string message)
{
// Keep track of original color so we can set it again.
var originalColor = Console.ForegroundColor;
Console.ForegroundColor = color;
Console.WriteLine(message);
Console.ForegroundColor = originalColor;
}
static void DisplayAvailableCommands(Dictionary<string, Command> commands)
{
// We always want a line above the commands
Console.WriteLine("Available commands:");
foreach (string key in commands.Keys)
{
var command = commands[key];
Console.WriteLine($"{key}. {command.Description}");
}
}
static void Draw()
{
Coloration(ConsoleColor.DarkGreen, "You chose to draw!");
}
static void Stay()
{
Coloration(ConsoleColor.DarkGreen, "You chose to stay!");
}
}
}
Adding new commands will be a breeze. And you can further refactor this to even smaller single-purpose methods. Each command could have its' own class in the event that your commands become more complicated (and in a real app, they will. Trust me). You can refactor the REPL to its' own class/method as well (take a look at this implementation I did a while back for example).
Anyway, this is my $.02 on a more correct way you could build a user interface of this nature. Your current solution is going to work, but it's not going to be fun to work with long-term. Hopefully this helps.
use a while loop to continuously ask for input if not valid, then check the input with a switch statement
bool flag = false;
while(!flag)
{
switch(input1)
{
case "1":
flag = true;
break;
case "2":
flag = true;
break;
default:
Coloration(ConsoleColor.Red, "Please enter a valid answer.");
break;
}
}
So I have no idea why it's not deleting the actual string from the WebsiteList, it's weird because it does delete from the ProxyList.
When debugging it says that it does delete something because the websiteList.Count gets lower after running through webisteList.Remove(website);
But it doesnt delete the string, it keeps looping through the same string.
foreach (var website in websiteList.ToArray())
{
var webSplit = website.Split(')');
foreach (var proxy in proxyList.ToArray())
{
if (proxyList.Count > 0)
{
if(websiteList.Count > 0)
{
var proxySplit = proxy.Split(':');
int Port;
bool convert = Int32.TryParse(proxySplit[1], out Port);
if (this returns true)
{
Console.WriteLine("Removing proxy");
proxyList.Remove(proxy);
websiteList.Remove(website);
}
if (this returns true)
{
Console.WriteLine("Removing proxy");
proxyList.Remove(proxy);
websiteList.Remove(website);
}
}
}
else
break;
}
}
You are repeatedly deleting from the same proxyList (i.e. you are repeating the whole inner loop as many times as there are websites). Why are those 2 loops nested? The websites seem not to be related to the proxies. Only if the proxy list would be extracted from a website, nesting would make sense.
Are these 2 lists supposed to have the same length and to have proxies belonging to websites at the same index? If this is the case, loop using a for-loop and loop in reverse order to avoid messing up the indexes.
for (int i = websiteList.Count - 1; i >= 0; i--) {
if (<condition>) {
proxyList.RemoveAt(i);
websiteList.RemoveAt(i);
}
}
If you had a class for the websites, this would simplify manipulating things belonging together. It also has the advantage that you can add additional logic belonging to websites and proxies (like extracting the port number):
public class Website
{
public string Site { get; set; }
public string Proxy { get; set; }
public int Port {
get {
string[] proxySplit = proxy.Split(':');
int portNo = 0;
if (proxySplit.Length == 2) {
Int32.TryParse(proxySplit[1], out portNo);
}
return portNo;
}
}
}
Now the list is of type List<Website> and contains both, the websites and the proxies
You can delete by using the for loop as before or use LINQ and create a new list containing only the desired items
websiteList = websiteList.Where(w => <condition using w.Site, w.Proxy, w.Port>).ToList();
Note: There is a System.Uri class for the manipulation of uniform resource identifiers. Among other things it can extract the port number. Consider using this class instead of your own.
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");
}
}
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 ++;
}
can anyone help me how to resolve the out of memory error on my asp page? im using linq to sql.. after adding data several data.. like more than 10 rows. in the grid. an out of memory error occurs.. attached herewith is my add function..
public ServiceDetail checkservicedetailid()
{
string ServiceName = ViewState["Tab"].ToString();
ServiceDetail checkservicedetailid = ServiceDetails_worker.get(a => a.ServiceName == ServiceName && a.MarginAnalysisID == checkmarginanalysisid().MarginAnalysisID).SingleOrDefault();
return checkservicedetailid;
}
public IEnumerable<ServiceDetail> get(Expression<Func<ServiceDetail, Boolean>> express)
{
return ServiceDetailsDB.ServiceDetails.Where(express);
}
protected void btnSaveEmptyOC_Click(object sender, EventArgs e)
{
try
{
if (checkservicedetailid() != null)
{
CashExpense tblCashExpenses = new CashExpense();
Guid CashExpensesID = Guid.NewGuid();
tblCashExpenses.CashExpensesID = CashExpensesID;
tblCashExpenses.ServiceDetailsID = checkservicedetailid().ServiceDetailsID;
tblCashExpenses.Description = txtDescriptionEmptyOC.Text;
tblCashExpenses.Quantity = Decimal.Parse(txtQTYEmptyOC.Text);
tblCashExpenses.UnitCost = Decimal.Parse(txtUnitCostEmptyOC.Text);
tblCashExpenses.CreatedBy = User.Identity.Name;
tblCashExpenses.DateCreated = DateTime.Now;
tblCashExpenses.CashExpensesTypeID = "OTHER";
CashExpenses_worker.insert(tblCashExpenses);
CashExpenses_worker.submit();
//Clear items after saving
txtDescriptionEmptyOC.Text = "";
txtQTYEmptyOC.Text = "";
txtUnitCostEmptyOC.Text = "";
ValidationMessage.ShowValidationMessage(MessageCenter.CashExpenseMaintenace.InsertOC2, "SaveEmptyOC", this.Page);
MyAuditProvider.Insert(this.GetType().ToString(), ViewState["MarginAnalysisID"].ToString(), MessageCenter.Mode.ADD, MessageCenter.CashExpenseMaintenace.InsertOC2, Page.Request, User);
divOtherCost.Visible = false;
grd_othercost.Visible = true;
btnaddothercost.Visible = true;
}
else
{
//Displays a Message on the Validation Summary (Service Id does not exist)
ValidationMessage.ShowValidationMessage(MessageCenter.CashExpenseMaintenace.SaveServiceDetailOC, "SaveEmptyOC", this.Page);
}
}
catch
{
//Displays a Message on the Validation Summary (Error on Saving)
ValidationMessage.ShowValidationMessage(MessageCenter.CashExpenseMaintenace.InsertOCError, "SaveEmptyOC", this.Page);
}
finally
{
//Rebinds the Grid
populategrd_othercost();
}
}
I'm guessing from your code here:
ServiceDetail checkservicedetailid = ServiceDetails_worker.get(
a => a.ServiceName == ServiceName &&
a.MarginAnalysisID == checkmarginanalysisid().MarginAnalysisID
).SingleOrDefault();
that .get() is taking a Func<SomeType, bool>, and you are doing something like:
var row = dbCtx.SomeTable.Where(predicate);
(please correct me here if I'm incorrect)
This, however, is using LINQ-to-Objects, meaning: it is loading every row from the table to the client and testing locally. That'll hurt memory, especially if a different db-context is created for each row. Additionally, the checkmarginanalysisid() call is being executed per row, when presumably it doesn't change between rows.
You should be testing this with an Expression<Func<SomeType, bool>> which would be translated to TSQL and executed at the server. You may also need to remove untranslatable methods, i.e.
var marginAnalysisId = checkmarginanalysisid().MarginAnalysisID;
ServiceDetail checkservicedetailid = ServiceDetails_worker.get(
a => a.ServiceName == ServiceName &&
a.MarginAnalysisID == marginAnalysisId
).SingleOrDefault();
where that is get(Expression<Func<SomeType, bool>>).
I tried all of the solution given to me both by my peers as well as the solution provided here, from GC.Collect, to disposing linq datacontext after use etc. however the error keeps on occurring, i then tried to remove the update panel, Ive read a site that showed how ridiculous update panel when it comes to handling data esp when a function is done repeatedly. And poof! the memory problem is gone!