Solving Redirect Loop - c#

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");
}
}
}
}

Related

Update sql database without blanks fields

I am trying to figure out a way for my program not to update the sql database if some fields are blank when I hit the submit form. Right now when I submit it to the sql database, if the fields are blank, it updates it as blank. Is there a way for my code not to behave like this?
Thanks
//field names in the table
string update = #"UPDATE Master_List
SET Date_Complete1 = #Date_Complete1, Pass_Fail = #Pass_Fail, CRC_Number = #CRC_Number, QN_Number = #QN_Number, Notes = #Notes WHERE Job_Number = #Job_Number"; //parameter names
using (SqlConnection conn = new SqlConnection(connString)) //using allows disposing of low level resources
{
try
{
conn.Open();//open new connection
command = new SqlCommand(update, conn); // create the new sql command object
// Read value from form and save to the table
command.Parameters.AddWithValue(#"Job_Number", jobTxt.Text);
command.Parameters.AddWithValue(#"Pass_Fail", comboBox1.Text);
command.Parameters.AddWithValue(#"Date_Complete1", opBox1.Text);
command.Parameters.AddWithValue(#"CRC_Number", crcTxt.Text);
command.Parameters.AddWithValue(#"QN_Number", qnTxt.Text);
command.Parameters.AddWithValue(#"Notes", notesTxt.Text);
command.ExecuteNonQuery(); // Push form into the table
}
catch (Exception ex)
{
MessageBox.Show(ex.Message); // If there is something wrong, show the user message
}
}
Assuming that you want to update some of the fields if one or more fields are blank, then you can do this:
UPDATE Master_List
SET Date_Complete1 = ISNULL(NULLIF(#Date_Complete1,''),Date_Complete1),
Pass_Fail = ISNULL(NULLIF(#Pass_Fail,''),Pass_Fail),
CRC_Number = ISNULL(NULLIF(#CRC_Number,''),CRC_Number),
QN_Number = ISNULL(NULLIF(#QN_Number,''),QN_Number),
Notes = ISNULL(NULLIF(#Notes,''),Notes)
WHERE Job_Number = #Job_Number
If you don't want any fields to update if any fields are blank, then just check them in an if statement.
Perform checks on your input data before your sql code is executed.
simply return out of the function if any checks you want to do fail e.g.
If(string.IsNullOrEmpty(variable to check))
... Return or configure error message for user ...
Or perform some logic to show the user you dont want blank fields.
If you are going to validate that you should change your database field properties to do that task.
if you want to do this with some code you should add something like this:
bool val = true;
if (jobTxt.Text.Trim() == string.Empty) {
val = false;
}
if(val==true){
command.ExecuteNonQuery();
}
else{
MessageBox.Show("Some field is empty")
}
and repite the sentence if for each textbox you want to do a validation.
i hope this help you.
You can say which textbox is empty on the else sentences on the textbox.

Check if user ID exist in SQL database

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");
}
}

Confirm Form Resubmission on browser popup duplicates the record

I am developing an application in which their exist a problem. When i click on to submit button, the data is inserted into db. But when i press ctrl+R or f5 a chrome or IE pop up occurs which says Confirm Form Resubmission. when i click continue then the record is duplicated into database.
My question is,
Why is this popup occuring? because of the postback? if because of postback then do my code have any issues or it occurs with every body when doing postback.
Will using mvc will solve this issue completely?
My code:
protected void btnSubmit_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
paramArray = new string[9];
paramValues = new object[9];
try
{
paramArray[0] = "#AccountNumber";
paramValues[0] = (!string.IsNullOrEmpty(this.txtAccountNumber.Value) ? this.txtAccountNumber.Value.Trim() : string.Empty);
paramArray[1] = "#OpeningBalance";
paramValues[1] = (!string.IsNullOrEmpty(this.txtOpeningBalance.Value) ? Convert.ToDouble(this.txtOpeningBalance.Value.Trim()) : 0.00);
paramArray[2] = "#ClosingBalance";
paramValues[2] = (!string.IsNullOrEmpty(this.txtClosingBalance.Value) ? Convert.ToDouble(this.txtClosingBalance.Value.Trim()) : 0.00);
paramArray[3] = "#PaymentMode";
paramValues[3] = this.ddlModeofPayment.Value;
paramArray[4] = "#PaymentDate";
paramValues[4] = this.dtPaymentDate.Value;
paramArray[5] = "#PaymentAmount";
paramValues[5] = (!string.IsNullOrEmpty(this.txtPaymentAmount.Value) ? Convert.ToDouble(this.txtPaymentAmount.Value.Trim()) : 0.00);
paramArray[6] = "#isAccount";
paramValues[6] = true;
paramArray[7] = "#UserId";
paramValues[7] = (!string.IsNullOrEmpty(this.User.Identity.Name.Remove(0, 7)) ? this.User.Identity.Name.Remove(0, 7) : string.Empty);
paramArray[8] = "#isProcessed";
paramValues[8] = default(bool);
var success = herlperUtility.ExecuteParameterizedQuery("{CALL asp_sp_InsertPayment(?,?,?,?,?,?,?,?,?)}", paramArray, paramValues);
if (!string.IsNullOrEmpty(success.Rows[0]["ReferenceNumber"].ToString()))
{
this.Page.Response.Redirect("AccountPaymentScreen.aspx?flag=1");
divSuccess.Attributes.Add("style", "display:block");
this.refId.InnerText = "<b>Success!</b> The " + success.Rows[0]["ReferenceNumber"] + " has been successfuly forwarded to the supervisor";
this.ClearFields();
}
else
{
this.divFailure.Attributes.Add("style", "display:block");
}
}
catch (Exception ex)
{
this.divFailure.Attributes.Add("style", "display:block");
this.divFailure.InnerText = ex.Message;
}
}
The solution to this is to follow the Post-Redirect-Get pattern. This means that after an HTTP POST in which you do some kind of transactional activity you redirect the client to an HTTP GET.
In a very simplistic way of thinking: GET should not modify anything, while POST is there to make changes.
For example, consider the following workflow.
The user presses submit on an shopping cart page (HTTP POST).
You validate that a credit card is valid and if so charge the
account and set your warehouse activities in motion
You show a screen confirming the order.
If everything goes well and you haven't redirected the client (e.g., you show a panel with a success message and hide the cart) and the client presses refresh, the order will be resubmitted which is probably not ideal for anyone other than accounts receivable.
Following the PRG pattern, after submitting the order you would redirect to a GET page (possibly with the order id in the query string so you have some way of referencing the order) and show your success message. This page can be refreshed as many times as the customer wants (with the added bonus of being bookmarkable) with no side-effects to your back end system or the customer's wallet.
It's worth noting that you don't have to be fanatical about this. In this example if the credit card validation failed you could choose to just display the results of the POST action and toggle an error message on your page. If the user refreshes the page, the validation will run and fail again but no changes will be made to your back end system.
As for MVC - It's not so much that it's easier to accomplish this (it is), it's that you end up thinking about these kinds of things a little more than when using WebForms which (for better or worse) hides these concepts behind an abstraction.

Check if user is logged in using sessions

I want to check if a user is logged in and if they are, deny them access to the registration and login pages. When a user logs in I'm setting these session variables:
HttpContext.Current.Session["LoggedIn"] = true;
HttpContext.Current.Session["FullName"] = (string)Reader["FirstName"] + " " + (string)Reader["LastName"];
Response.Redirect("Default.aspx");
And I'm checking them at the top of the register and login pages like so:
if ((bool)HttpContext.Current.Session["LoggedIn"])
{
Response.Redirect("Default.aspx");
}
However, when I try to go to the page while not logged in this exception gets thrown:
Object reference not set to an instance of an object.
I'm assuming it's ebcause the LoggedIn key doesn't exist because I only create it after a successful login.
So, how can I check if the LoggedIn key exists and if it doesn't, redirect the user to Default.aspx?
Thanks!
I think you can do a simple null check on this like....
if (HttpContext.Current.Session["LoggedIn"] != null)
{
// once inside this loop
// you can now read the value from Session["LoggedIn"]
Response.Redirect("Default.aspx");
}
you need to make shure that the object is not null before unboxing it
if(HttpContext.Current.Session["LoggedIn"]!=null)
{
if ((bool)HttpContext.Current.Session["LoggedIn"])
{
Response.Redirect("Default.aspx");
}
}
Why to avoid the default webforms authentication model altogether? Simply use web.config to define a restricted area, set all the settings correctly and you won't have to perform checks like this for every page.
But, if you want to reinvent the wheel....
You check for something that probably doesn't exist yet. You must modify your if-statement like this:
bool isLoggedIn = (HttpContext.Current.Session["LoggedIn"] == null ? false : (bool)HttpContenxt.Current.Session["LoggedIn"];
if (isLoggedIn)
{
Response.Redirect("Default.aspx");
}

C# visual if/else issue

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 ++;
}

Categories

Resources