Checking if a page IsValid even when CausesValidation is false - c#

I need to check the value of Page.IsValid on every load/postback of a page in order to perform some other logic.
However, IsValid cannot be called if Page.Validate() has not been called.
Page.Validate() will not be called if the control that posted back had CausesValidation set to false.
If I call Page.Validate() myself, it causes all the Validators on the page to display.
I currently have two solutions to this problem.
First method, I use a try catch around IsValid. I catch the exception that will occur if validation has not occurred. I then call Page.Validate, check the value of IsValid, then loop through all the Validators to mark them all as Valid so they do not appear on the page.
bool isValid = false;
try
{
isValid = this.IsValid;
}
catch (System.Web.HttpException exception)
{
if(exception.Message == "Page.IsValid cannot be called before validation has taken place. It should be queried in the event handler for a control that has CausesValidation=True and initiated the postback, or after a call to Page.Validate.")
{
//Validation has NOT occurred so run it here, store the result, then set all the validators to valid.
this.Validate();
isValid = this.IsValid;
foreach (IValidator validator in this.Validators)
{
validator.IsValid = true;
}
}
}
Second method, is to use reflection to get the field _validated from the underlying page itself. Then I do the same as the first method in calling Validate if the page hasn't been validated and then resetting all the Validators afterwards.
bool isValidated = (bool)typeof(Page).GetField("_validated", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(this);
bool isValid = false;
if (isValidated)
{
isValid = this.IsValid;
}
else
{
this.Validate();
isValid = this.IsValid;
foreach (IValidator validator in this.Validators)
{
validator.IsValid = true;
}
}
I do not like either of this solutions as I don't like coding by exceptions and I don't like using reflection to get at the Validated property as there must have been some reason it was kept private in the first place.
Does anyone else have any better solutions or any ideas?

I'd suggest you simply use your validators with the EnableClientScript option set to false.
This way, you will be able to call
if (this.Page.IsValid)
in your code.
If you want to validate a specific validation group, just use this line in server-side:
Page.Validate("ValidationGroupName")
Look at these examples of group validation

Related

Change Buttons to visible after a User logs in

I made an SQL database with a connection and a table with user and password. I managed to create a login following a guide. The code is working fine to login, but what I want to do is to show all other Buttons on the main Form after a user logs in.
I am using a Panel in the main Form to show the second Form. Clicking Buttons show a UserControl in the middle Panel.
I just want to update the Button.Visible value from false to true without opening a new main Form.
I can make the Buttons visible when the Form loads but not when I try to set a condition. I can't figure out how to set a condition that when a user logs in successfully, the other Buttons are set to visible and the login Button is hidden.
Part of code in the MainLogin UserControl.
The MainMenu.UserAutherised I added was to pass the userID from a TextBox to the UserAutherised() method in the MainMenu Form when the login is successful.
if (mread.Read() == true)
{
MessageBox.Show("Login successfull");
this.Hide();
MainMenu.UserAutherised(text_userID.Text);
}
Part of code in MainMenu: I did this trying to solve the problem.
I thought that setting a bool to true when a user successfully logs in, I could have then called the ShowButtons() method to set Buttons to visible:
public static bool UserAutherised(string user)
{
bool returnValue;
string _user ="true";
string _noUser ="false";
bool _userID = bool.Parse(_user);
bool _noUserID = bool.Parse(_noUser);
}
if (user == "")
{
returnValue = _noUserID;
return returnValue;
}
else
{
returnValue = _userID;
return returnValue;
}
I get the bool value as far as I can understand from debugging, but when I try to use the if statement in the ShowButtons() method, I can't figure out how to get the bool value from UserAutherised() to if(UserAutherised()) to show the Buttons when the value is true.
I hope I described the problem well enough.
EDIT 1:
I tried the same event Action syntax to get the position and access for the user logging in. In the MainLogin form i added the following:
public event Action<string> ACCESS;
public event Action<string> POSITION;
string userAccess, userPosition;
and then i added the following in the mread.Read if-statement:
Sqlcommand cmd_get_position_Access = new SqlCommand (
"SELECT, Access FROM Users WHERE position = #position AND Access = #Access", dataconnection);
SqlParameter _position = new SqlParameter("#position",
SqlDbType.NVarchar);
SqlParameter _access = new SqlParameter("#Access", SqlDbType.NChar);
cmd.Parameters.Add(_position);
cmd.Parameters.Add(_access);
userPosition = mread["position"].ToString();
userAccess = mread["Access"].ToString();
I get a NullReferenceException when trying to Invoke the new events so i added the following if-else statement to fix it:
if (ACCESS == null || POSITION == null)
{
return;
}
else
{
ACCESS.Invoke(userAccess);
POSITION.Invoke(userPosition);
}
In the MainMenu button click event:
var userLogin = new MainLogin();
panel_Main.controls.Add(userLogin);
userLogin.userLogged += UserLogged;
userLogin.ACCESS += UserAccess;
userlogin.POSITION += Position;
userLogin.Show();
When debugging i can see that i get the Access value from database table. But when i try to use a method with if-statements but the conditions are skipped even when true. I also tried the switch-statement but same thing happens to cases. They are skipped. For example if admin login i get access yellow but case is skipped. Same thing happens to the if-statements conditions. Access is yellow and condition is true but if-statement is skipped. Why are they skipped when conditions are true?
private void UserAccess(string access)
{
switch (access)
{
case: "yellow":
userAdmin();
break;
case: "green":
userGreen();
break;
default:
break;
}
}
EDIT 2:
I found the problem. It turns out to be in the User table. Access was set to nchar data type which add spaces to the value. Access was getting the string "yellow ". I changed data type to varchar and it solved the issue.
Why are you using static method to access MainMenu?
I think it would be better to declare event in MainLogin form like:
public event Action<string> userLogged;
and invoke it after this.hide:
userLogged.Invoke(text_userID.Text);
And in MainMenu form create a handler for this event:
void UserLogged(string user)
{
if (user != "")ShowButtons();
}
And subscribe to userLigged event before showing MainLogin form like:
MainLogin loginForm = new MainLogin();
loginForm.userLigged += UserLogged;
loginForm.Show();

Can the ErrorProvider be queried to see if it has set any errors?

I have this code to do some basic sanity checking before posting a record:
if (string.IsNullOrWhiteSpace(textBoxFirstName.Text))
{
errorProvider.SetError(textBoxFirstName, "Enter a first name");
}
if (string.IsNullOrWhiteSpace(textBoxLastName.Text))
{
errorProvider.SetError(textBoxLastName, "Enter a last name");
}
...but I want to then do something like this to exit the handler if either of those conditions has been met:
if (errorProvider.SetErrorCount > 0) then return;
...but I see no way to do that. I don't want to have to write an "OR" statement to see if either of the textBoxes I'm checking are empty and then short circuit the handler that way.
Is there a way to tell whether the errorProvider is "dirty" to avoid cluttery code?
Write a method and pass it the error message and the control. Have a counter variable and increase the counter within the method. Here is some pseudocode:
private int errorCount;
SetError(Control c, string message)
{
errorProvider.SetError(c, message);
errorCount++;
}
One option would be to use the GetError method off of the ErrorProvider.
// possibly use a backing field for all controls to evaluate
private readonly Control[] textBoxes = new[] { textBoxFirstName, textBoxLastName };
// helper property to evaluate the controls
private bool HasErrors
{
get { return textBoxes.Any(x => !string.IsNullOrEmpty(errorProvider.GetError(x)); }
}

Validate single validation groups step by step in code behind

I have three sections of a form that are contained in jquery tabs. I want to have each tab have it's own validator on it so that if there are validation errors on that form, it is easy to see which forms the user needs to re-do. The problem I am running into is that when I try something like this:
private void ValidateTabOne()
{
Page.Validate("t1");
if (!Page.IsValid)
cvt1.IsValid = false;
}
private void ValidateTabTwo()
{
Page.Validate("t2");
if (!Page.IsValid)
cvt2.IsValid = false;
}
protected void btnSave_Click(object sender, EventArgs e)
{
ValidateTabOne();
ValidateTabTwo();
if (Page.IsValid)
{
//do the save
}
}
cvt2 will always be invalid if anything in the t1 group is invalid (regardless of if t2 group is valid or not) because I Validate("t1") first.
I'd still like a way to do this in the code behind. How can I validate a single group at a time, or "reset" the validation to exclude the previous groups in the Page.IsValid check?
I know that worst case I can write a huge statement to check each validator for IsValid but would much rather use the validation groups.
The best way I have found to do this for now is to use Page.GetValidators as such:
foreach (IValidator v in Page.GetValidators("t1"))
{
if (!v.IsValid)
{
cvt1.IsValid = false;
return;
}
}
cvt1.IsValid = true;
Beforehand I do my custom validation, this just checks to make sure all the required validation is already accounted for.

How set null a variable from session when the user leaves a page

I want to set one variable from session to null
Session["my_variable"] = null;
I tried with OnUnload like this
protected override void OnUnload(EventArgs e)
{
base.OnUnload(e);
Session["my_variable"] = null;
}
but it doesn't work right, it sets the variable while the user is on page but I want to set it null whet is leaves page
Your function/event will be fired as soon as page is served to client, because it is a server side event. You might use Viewstate but still it cannot be implemented as navigation does not send any event to server while clientside scripting can help.
This functionality can be implemented by java script on-unload event. You have to send a request to server to remove or put null in particular session value ( as session is key-value object ). Your question is best explained at Asp Forum
But be careful. This event might fire only on navigation by some browser. you might have to do some code-work to implement what you want.
Why dont you are making use of ViewState inplace of Session Variable.
viewstate variable automatically get removed once you leave page
here is example how to use it
protected DataSet MyDataSet
{
get
{
if(ViewState["MyDataSet"] == null)
{
return null;
}
else
{
return (DataSet)ViewState["MyDataSet"];
}
}
set
{
ViewState["MyDataSet"] = value;
}
}

Server-side RequiredFieldValidators not working

I have a form representing a survey that is dynamically generated based on some database configuration. I have a custom server control for rendering the survey (SurveyRenderer) which contains custom server controls for rendering questions (QuestionRenderers). I dynamically add RequiredFieldValidators for questions if they are flagged as being required. I add these validators to the SurveyRenderer's control collection.
The gist of the code...
// In SurveyRenderer.CreateChildControls()...
foreach (QuestionRenderer questionRenderer in questionRenderers)
{
if (questionRenderer.Question.IsRequired)
{
Controls.Add(CreateRequiredValidator(questionRenderer));
}
}
The client-side validation works fine -- if someone has omitted a required question, the validators catch it and the form doesn't validate. However if I turn off JavaScript and submit an invalid form, the validators do not seem to work.
On the server-side I am calling Page.Validate() and checking Page.IsValid in the submit button click event handler. Despite submitting a form where required questions have been left blank - something that would be caught client-side - on the server-side Page.IsValid remains True.
// In SurveyPage.aspx...
public void btnSubmit_Click(object sender, EventArgs e)
{
Page.Validate();
if (Page.IsValid)
{
// Always get here, even though the form is not valid and would
// have been caught client-side...
}
}
Should I be adding the validators to the Page's Control collection, rather than the SurveyRenderer? How come it works on the client-side but not server-side?
UPDATE: My QuestionRenderer is annotated with:
[ValidationProperty("IsValid")]
And the IsValid get method is like so:
// QuestionRenderer.IsValid
public bool IsValid
{
get
{
EnsureChildControls();
if (Question.IsRequired && QuestionIsNotAnswered())
{
return false;
}
return true;
}
}
If I set a breakpoint and step through, I can see that QuestionRenderer.IsValid is being fired OK. It is returning false when it should do. If I go fine-grained and call in btn_submitClick:
// In SurveyPage.aspx...
public void btnSubmit_Click(object sender, EventArgs e)
{
foreach (IValidator validator in Page.Validators)
{
validator.Validate(); // this calls through to QuestionRenderer.IsValid, which returns false...
bool valIsValid = validator.IsValid; // yet this is set to True
}
}
So validator.IsValid is true, even though the call to QuestionRenderer.IsValid returns false. So maybe I haven't wired something up correctly? Is using [ValidationProperty("IsValid")] not enough?
actually, validation uses Page.Validators where all the validators are stored (the actual routine is quity tricky) - so it does not matter, where you add them.
source of BaseValidator
protected internal override void OnInit(EventArgs e)
{
base.OnInit(e);
this.Page.Validators.Add(this);
}
i would leave them in th view, as you could use object sender-parameter (which represents the validator) to get the associated control ...
i believe, your CreateChildControls - which does the attaching of the validators - is called to late, so it misses the validation phase ...
could you maybe try to call EnsureChildControls in OnLoad-event, to see if it changes something?
another chance might be, that your validators are not visible or disabled...
EDIT
according to your edits, i would encourage you to use a CustomValidator - a RequiredFieldValidator will return true on each case (property is true or false), because it is not empty :)

Categories

Resources