Regular Expression Validate() yields NullReference(ASP.NET) - c#

I am having problems using a ASP.NET Regular Expression Validator on text boxes.
This is a condensed version of my code:
RegularExpressionValidator regex = new RegularExpressionValidator();
regex.ID = "TextBoxRegExValidator" + ((AVPEditControl)avpControl).ThisFieldRID.ToString(); //random name
regex.ControlToValidate = ((AVPEditControl)avpControl).TextControlID; //this is valid.
regex.ValidationExpression = "\d{3}-\d{2}-\d{4}";
regex.Text = "epic fail";
//later, in an event handler
regex.Display = ValidatorDisplay.None;
regex.ErrorMessage = "";
regex.Validate(); //ERROR
bool valid = AVPEdit.Validator.IsValid;
Where I marked "ERROR" Is where I get a NullReferenceException thrown. I do not see what I am missing here, because I confirmed with a debugger that regex is not null in that context, and neither is the control that it validates.
I wish to have more fine grained control over how the error message is displayed,so thats why I chose not to hook regex into any Panels or such.
Why would I possibly be getting a null reference from that? (Is this a bug in .NET?)
Also, note that this works when I set Visible to 0, but that makes it so IsValid is always true.

All the ASP.NET validators must be part of a Page in order to function. You'll note that the Validate method does not return a value; this is because it is not intended to be used the way you're using it.
Inside the Validate method, it is attempting to look up the control by its ID and without a parent naming container, it has no ability to do so. The way you're doing it, it has no value to validate against (because it won't be able to find the control).
I would do one of the following:
1) Put the validator in the ASPX, then use its Validate method and check the IsValid property afterwards. Just set Display to None and it shouldn't show up in your UI.
2) Just run the regex manually. You're writing a lot more code here than would be necessary if you would just use Regex.IsMatch.
(Note that if you use Reflector, browse to RegularExpressionValidator, you'll see where it will attempt to call out to this.NamingContainer among other things that would be null without being part of a control collection)

I think you should add it to your controls collection, maybe inside an invisible div control to make it work.
But If you want to validate your textbox programmatically, why don't you just write a method that uses your pattern to validate control and returns validity ?

I think if you want to use code behind for validation, you can use something like this
Match m = Regex.Match(yourtext,"\d{3}-\d{2}-\d{4}")
if(m.Success)
{
//valid
}
else
{
//invalid
}

Related

Any better way to handle user input validation?

I have a 3 layered system of presentation, logic, and data access. In my logic layer, I have a Validate() method which makes sure that the data that's about to get forwarded to the data access layer is valid for the database (no nulls where nulls are not allowed, and so on).
On top of that, in the .aspx presentation layer, we have some user-friendly error checking and validation, directly checking the controls on the web form. My problem is the ValidateInput() method in the code behind which checks the controls, it's several hundreds of lines long and really annoying to maintain. The code for checking the data is far far longer than the code that does the actual work.
What I've got looks like this:
private List<string> ValidateInput()
{
List<string> errormessages = new List<string>();
if (LastNameETextBox.Text.Trim() == String.Empty)
{
errormessages.Add("Last name required.");
}
if (FirstNameETextBox.Text.Trim() == String.Empty)
{
errormessages.Add("First name required.");
}
//etc. etc.
}
We have a nice styled notification box hidden in the master page that gets turned from Visible false to true when we call it, creating the "illusion" of an overlaying box. It looks really nice and works really well so we want to use it. The idea is that we gather up all the errors for the whole form, put them in a list, and then send that list to the notification box, which then gives you all the errors in one nice list.
But the Validate() is just a torturous amount of "if" statements and it's hard to keep track of. Is this just the nature of input validation, or is there some other, better way of handling this?
I think you can able to avoid using these kind of If statements using a Generic function.
My suggestion is to define a function like this
private List<string> ValidateInput(string ErrorMessage, TextBox txtInput, ValidatationType validationType)
{
List<string> errormessages = new List<string>();
if (validatationType == ValidationType.NoNullValues)
{
if (txtInput.Text.Equals(String.Empty))
{
errormessages.Add(ErrorMessage);
}
}
if (validatationType == ValidationType.Integer)
{
int number;
if (Int32.TryParse(value, out number))
{
errormessages.Add(ErrorMessage);
}
}
// etc. etc.
}
Enum ValidationType
enum ValidationType
{
NoNullValues,
Integer,
// etc
}
Please modify the function. Also checks the syntax, I am using notepad to write the code.
This approach also helps you to achieve re-useabilty if you are use all validation methods in a separate class.
Thanks
Couple of the different ways that I had handled it (in different projects) :
Use custom control library - controls were simply extending existing ASP.NET/3rd party controls to add validation logic which was controlled by properties such as IsMandatory, MandatoryMessage etc. Properties were typically set at the design-time (and were not backed by view-state). The validation logic would accumulate error messages in the message collection exposed by base page. Another variant had used user controls combining ASP.NET controls along with validators but frankly speaking, ASP.NET validators sucks.
Essentially a base page class had a validation logic that would traverse the control collection within the page and then perform validation based on control type. The page would offer a registry to register control to validate, type of validations and error message to display. There was also method to un-register/skip control validation that was used primarily to skip control traversal within control such as repeater/grid-view.
For client-side(browser side) validation, I had used jquery validation (or own JS library). In both cases above, the validation logic would also emit necessary start-up scripts to set-up the client-side validation - however, #2 could generate a single start-up script (with less size) while #1 entails generating a start-up script per control instance. From flexibility perspective, #1 is better and fits nicely in control based development approach. #2 centralizes your validation logic at one central place (i.e. a base page) which can be very handy.
a) Create an validation type enum to enumerate all types of validation you want to perform. (In your code you are doing string null checking for both controls which are both textboxes, its unnecessary repetition of code logic)
b) Create a class of constants / or resource file that holds all the error messages.
c) Write a function that takes a control, Validation type enum, arguments for validation and error message id. It will check the type of control and perform validation as indicated by enum. If error, error message is added to your "errorMessages" collection.
enum ValidationType{
NullCheck,
IsNumber,
RangeCheck,
....
}
class ErrorMessages{
const string FNEMPTY = "First Name is empty";
....
}
class BusinessObject{
function ValidateControl(Control cntrl, ValidationType type, object[] args, string message)
{
if(cntrl is TextBox)
{
if(cntrl as TextBox).Text.Trim() == String.Empty
errorMessages.Add(message);
}
...
}
}
Now you can call the above function on every control you want to validate. One more improvement will be to Implement a base class for all your controls that holds the corresponding error message collection in a property (Dictionary<ValidationType,String>). Then you can modify the validation function to accept an array of ValidationType enum to perform several validation in one call. Each control will give you its error message for every validation type in its property we created in the base class.
Hope this helps.
Thanks
Ven

How to solve cast issues in ValidationRule classes' properties?

I need to create a few tests for the user roles in a web application. To minimize the description, one of the tests involves checking if a menu entry is displayed or not for an user.
For this test, I use a table called UserRoles, that looks like this:
sUserName bDoesntHaveMenuX
User1 1
User2 0
User3 1
bDoesntHaveMenuX is of type bit.
I have a class derived from ValidationRule that checks if a certain text is present in a page, based on a XPath expression to locate the node where to look for the text.
The public properties of this class are:
string XPathExpression
string Text
bool FailIfFound
The last one dictates if the rule should fail if the text is found or not found.
In the test I added a datasource for the table mentioned in the beginning, called DS.
For the request I'm interested in I added a new instance of my validation rule class, with the following values:
Text=MenuX
XPathExpression=//div[#id='menu']//td
FailIfFound={{DS.UserRoles.bDoesntHaveMenuX}}
Unfortunately, this doesn't work.
The reason seems to be that the data binding process creates a context variable
DS.UserRoles.bDoesntHaveMenuX has the value "False" or "True". The value is a string, so the binding results in a casting error.
My options, as far as I can think of, are:
Change the validation rule to accept strings for FailIfFound. Not a valid
option, for 2 reasons: it's a hack and the same rule is used in
other places.
Make a new validation rule that will use the above mentioned one,
and implement the FailIfFound as string. I also don't like this, for
the same reason as above. It's a hack.
Make the test coded and do the proper cast before passing the data
to the validation rule. I don't like this one because I prefer to
have the test as coded only if there is no other way.
Which brings me to the question. Is there another way?
Thank you.
So the fundamental issue is that you have no control over how the data-binding treats the 'bit' data type, and it's getting converted to string instead of bool.
The only solution I can think of (which is sadly still a bit of a hack, but not so egregious as changing FailIfFound to string) is to create a WebTestPlugin, and in the PreRequestDataBinding or PreRequest event, convert the value from string to bool. Don't forget to add the plugin to your test(s) (easy mistake I have made).
Then when the validation rule is created it should pick up the nice new bool value and work correctly.
e.g.
string val = e.WebTest.Context["DS.UserRoles.bDoesntHaveMenuX"].ToString();
e.WebTest.Context["DS.UserRoles.bDoesntHaveMenuX"] = (val == "True");
I didn't actually try this... hope it works.
EDIT: round two... a better solution
Change the FailIfFound property to string (in a subclass as you mentioned), so it can work properly with data-binding.
Implement a TypeConverter that provides a dropdown list of valid values for the property in the rule's PropertyGrid (True, False), so in the GUI it looks identical to the rule having FailIfFound as a bool. You can still type your own value into the box when necessary (e.g. for data-binding).
Add the path of the .dll containing the TypeConverter code to your test project's References section.
This is what I have started doing and it is much more satisfying than having to type 'True' or 'False' in the property's edit box.

asp:RequiredFieldValidator does not validate hidden fields

It seems that ASP.NET validators do not validate hidden fields. I get messages like this:
Control 'hiddenField' referenced by the ControlToValidate property of 'hiddenFieldValidator' cannot be validated.
I have an <asp:HiddenField> in my page which gets filled client side with some value. I need this to be present once on the server so I added a RequiredFieldValidator to it.
And it does not work!
As I see it, as a workaround, I can:
1. use a custom validator and not tie it to the hidden field, just call a method on OnServerValidate;
2. Use a <asp:TextBox> with a CSS style display:none and it should work.
But I want to make sure I am not missing something here. Is it possible or not to validate a hidden field in the same way as the other text fields? O maybe a third, more elegant option?
TIA!
#Peter's answer got me thinking, what does ControlPropertiesValid actually check??
Looking at the MSDN topic it looks for, among other things, the ValidationPropertyAttribute.. Hhmm, so if we just derive from HiddenField and decorate the new class with ValidationPropertyAttribute set to Value (for my purposes) then 'everything just works'. And it does.
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Partner.UserControls {
[ValidationProperty("Value")]
public class HiddenField2 : HiddenField {
} // nothing else required other than ValidationProperty
}
Usage - make sure you register the assembly containing the control:
<%# Register Assembly="MyApp" Namespace="MyApp.Controls" TagPrefix="sw" %>
And in your Page/UserControl content:
<sw:HiddenField2 ID="hidSomeImportantID" runat="server" />
All validators will work with this. The added benefit is that if you (like me) are using a custom validation function you can easily evaluate the HiddenField2.Value because it is contained in the args.Value field (on server side this is ServerValidateEventArgs).
Just as the exception message you're getting says, it seems HiddenField controls can't be targeted by the standard validation controls directly. I would go with the CustomValidator workaround.
Here is the workaround I came up with, because unfortunately I couldn't find any reliable way to validate using the RequiredFieldValidator OR the CustomValidator out of the box. If you leave the ControlToValidate property empty it yells at you. All you have to do is create a custom control like the one below:
public class HiddenFieldValidator : RequiredFieldValidator
{
protected override bool ControlPropertiesValid()
{
return true;
}
}
By overriding the properties valid check so that it always returns true it no longer cares that you are using a HiddenField and it will pull the value out of it and verify without issue.
This is a response to the solution by Scotty.NET. I just don't have enough reputation to reply.
+1 to Scotty.NET!
For those of us who don't know enough about .NET and compiling and such, this may help simplify usage of his answer for someone else.
I wanted to make use of it in a website using Visual Web Developer 2010 Express:
1) I saved the derived HiddenField2 in /App_Code as HiddenField2.cs, with one change --> namespace Controls
2) Then, to register the control:
a) On the page, <%# Register Assembly="App_Code" Namespace="Controls" TagPrefix="local" %>
b) In web.config, within system.web > pages > controls, <add tagPrefix="local" namespace="Controls" assembly="App_Code" />
3) And, finally, of course, refer to it as <local:HiddenField2 ...>.
It does make for funky code coloring. Probably fairly easy to improve the namespace to handle that. Works wonderfully for me in my local environment; guess I don't know it won't have problems on a live server.
Additional reference:
extending asp.net control in the website project
To expand on #Anders' solution, with a CustomValidator approach, you can very easily grab the value of a standard HiddenField control by first finding the control, casting it, and then using its UniqueID to look its value up in the Page.Request.Form[].
Example 1: Improving the Compare Validator
This example may be a bit more local to your implementation. The below is an improved version of the CompareValidator.EvaluateIsValid() method call, in order to add support for validating HiddenField controls. Note that this technique can be applied to any validator, instead of wrapping the HiddenField in a custom control, but that the ControlPropertiesValid method should also be overriden to recognize and return true in the presence of a HiddenField.
...
private new string GetControlValidationValue(string id)
{
var control = this.NamingContainer.FindControl(id);
if (control != null)
{
if (control is HiddenField)
{
return Page.Request.Form[((HiddenField)control).UniqueID];
}
else
{
return base.GetControlValidationValue(id);
}
}
}
protected override bool EvaluateIsValid()
{
// removed 'base.' from the call to 'GetControlValidationValue'
string controlValidationValue = GetControlValidationValue(base.ControlToValidate);
if (controlValidationValue.Trim().Length == 0)
{
return true;
}
bool flag = (base.Type == ValidationDataType.Date) && !this.DetermineRenderUplevel();
if (flag && !base.IsInStandardDateFormat(controlValidationValue))
{
controlValidationValue = base.ConvertToShortDateString(controlValidationValue);
}
bool cultureInvariantRightText = false;
string date = string.Empty;
if (this.ControlToCompare.Length > 0)
{
//same as above
date = GetControlValidationValue(this.ControlToCompare);
if (flag && !base.IsInStandardDateFormat(date))
{
date = base.ConvertToShortDateString(date);
}
}
else
{
date = this.ValueToCompare;
cultureInvariantRightText = base.CultureInvariantValues;
}
return BaseCompareValidator.Compare(controlValidationValue, false, date, cultureInvariantRightText, this.Operator, base.Type);
}
...
Example 2: Custom Dynamic Validator
This example is a bit more complicated than the first one. I regularly use custom dynamic validators that are enabled or disabled based on the value of another control on the page (e.g., if that box is checked then this textbox is required; otherwise it does not need to be validated). One such validator is my DynamicRequiredFieldValidator, which inherits from the built-in RequiredFieldValidator. The dynamic validator has two custom attributes, ControlThatEnables and ControlValueThatEnables, that are used to decide whether or not the validator should be turned on. The below is a snippet from the method that determines whether or not the validator should be enabled, but note that, as above, this same technique can be applied to validating a HiddenField without the need to wrap it in a custom control.
...
var enablingControl = this.NamingContainer.FindControl(ControlThatEnables);
if (enablingControl != null)
{
if (enablingControl is HiddenField)
{
var hfValue = Page.Request.Form[((HiddenField)enablingControl).UniqueID];
isValidatorEnabled = hfValue == ControlValueThatEnables;
}
}
...
Final Thoughts
The implementation decision is ultimately up to you, as the developer, but my preference is to wrap existing validators in custom controls, rather than to wrap things like HiddenFields, TextBoxes, DropDownLists, etc. in custom controls. I have two main reason for preferring this solution: (1) wrapping the validators take only a few minutes more than just adding the ValidationProperty, but provides significantly more flexibility and opportunity for further improvement of .NET validaton, e.g. one could point the FindControl calls to some custom method that searches for the desired control ID in the current NamingContainer (default) and then expands the search to the outer Page or the NamingContainer's parent if the control was not found; (2) IMHO if one is trying to improve validation, it is cleaner to make improvements to validation, and, contrarily, if one is trying to improve a WebControl, it is cleaner to make improvements to the WebControl.
I completely respect #Scotty's solution, and will be the first to admit that if it is the only change to be made, then his solution will save you 5 minutes more than this one. IMHO however, #Anders' is likely to be a better choice, in the long run.
I'd go with a CustomValidator client side
<script type="text/javascript">
function myMethod(source, args) {
args.IsValid = document.getElementById("<%= myValue.ClientID %>").value != '';
}
</script>
<asp:HiddenField ID="myValue" runat="server" />
<asp:CustomValidator runat="server" ClientValidationFunction="myMethod"
ErrorMessage="Value missing!" />

C# ASP.NET GetType() with WebUserControl issue

In the project I have some custom WebUserControls for form elements (they encapsulate some standard validators and other system specific functions). My user controls are "DropDownListField" and "TextBoxField". In the code behind of a page I have this code:
string parameterValue = null;
foreach (object control in myMultiView.Views[myMultiView.ActiveViewIndex].Controls)
{
if (control.GetType() == typeof(DropDownListField))
parameterValue = ((DropDownListField)control).Value;
if (control.GetType() == typeof(TextBoxField))
parameterValue = ((TextBoxField)control).Value;
}
For some reason the "if" statements always return false even when I step through the code and see that "control" is getting assigned my web user control. This code is in another place in the project exactly the same except in the other location the standard .net controls "TextBox" and "DropDownList" are used and in the other location the code works.
Does anybody know why this wouldn't work with web user controls?
UPDATE:
Hmm so in debugging I found this:
?control.GetType();
BaseType: {Name = "DropDownListField" FullName = "WebUI.UserControls.Fields.DropDownListField"}
?typeof(DropDownListField);
BaseType: {Name = "UserControl" FullName = "System.Web.UI.UserControl"}
So typeof is just recognizing they are user controls not the full type it seems.
Does anybody know how I would check for a specific user control type?
I'm guessing they aren't the same type, use debugging to find out the actual type.
Also, try using the 'is' keyword instead.
PS: It might be cleaner for you to say if (control is DropDownListField)
I don't recall if a view directly includes its children in Controls, but I wouldn't be surprised if Controls contained only one element, which would be a container of some sorts. Therefore, your controls are potentially in Controls[0].Controls or even further down. I would advise you create a method that finds the child recursively.
Actually, your controls should all implement a common interface (example:
interface ICustomFieldWithValue { string Value {get; set; }}
). Your resulting code would be much cleaner.
c2.GetType().ToString() == "System.Web.UI.WebControls.Label"

Is this a bug in ASP.NET 3.5?

In ASP.NET when I try to add a dynamic control (includes validation) to Placeholder or any other control container, the name of control become an important. For example, this is very normal, easy control adding code.
var control = LoadControl("TestUserControl.ascx");
control.ID = Guid.NewGuid().ToString();
PlaceHolder1.Controls.Add(control);
as you see, I'm giving guid to control's ID. In Runtime, this code fails, and compiler says this is a javascript error, and error message like ';' character expected, missing.. etc..
The problem is very interesting. Dynamically added ASP.NET control (includes validation), causes an error because of " - " character in dynamically named ID property (or anything like '-', '.',etc..).
When I refine my code like:
var control = LoadControl("TestUserControl.ascx");
control.ID = Guid.NewGuid().ToString().Replace("-", string.Empty);
PlaceHolder1.Controls.Add(control);
problem goes away :)
Is this a bug in ASP.NET 3.5? Why its look like a javascript error in page?
It's not a bug so much as misuse. You couldn't give a control an ID that included a - if you did it within the IDE, so it makes sense that attempting to do it dynamically should have unintended results. The math functions are riddled with peculiarities like this that aren't bugs. Sure MS probably could have put in a function in the property that checked for invalid characters in the ID before allowing it to be set, but that would be a runtime error anyway (which is what you have).

Categories

Resources