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!" />
Related
I am currently building a ASP.NET C# form. This form had many fields and many validations.
Which included:
Validate when the required checkbox is checked
Validate a dynamic form (e.g. additional address form generate dynamically when add address button click)
At first, I was planning to use ASP.NET form control to create all the fields and validations. But later on I found there is a plugin call jqueryvalidation, which simply provided what I need through Jquery.
Validate when the required checkbox is checked (http://jquery.bassistance.de/validate/demo/index.html)
Dynamic form (http://jquery.bassistance.de/validate/demo/dynamic-totals.html)
and my question is, if I am going to use this, would it be easier for me to create the form using standard HTML form tag instead of .NET control? Or can I still use .NET control?
I am quite struggle as I want to use the .NET control because I can obtain the value easily in code behind instead of Request.Form["fieldName"] but on the other hand, I feel not convenience to use the validation that .NET provided and I am not sure whether .net can create a dynamic form as easy as Jquery either.
Please advise. Thanks!
with validation plugin you can use "when required" case like this
$('#formSubmit').validate({
rules: {
ControlAspNetorSmtin: {
required: {
depends: function (element) {
if ($('#chkglobal').is(':checked')) {
return false;
} else {
return true;
}
}
}
}.... etc
If you are using ASP.NET MVC (which you probably should be) then your best bet would be to use auto-magic validation using model validation attributes and unobtrusive-validation. This would take care of client- and server-side validation with minimal effort (apart from defining the attributes).
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
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"
I am working on a quiz control in asp.net with dynamically created questions and options.
The main control is basically a container to hold all of the questions.
In design view users can add questions through a custom Collection Editor.
Everytime i add a question to the collection editor list it generates a question tag for me.
Inside each question object is a label and a n amount of Option objects that inherit the Radiobutton Control. Each of these Option objects in turn represent a option the user can select for each question.
This all works except i am now at the part where i want to be able to read the Checked value of each radiobutton. When i want to implement this quiz inside a page and check the questions i want to put a button in this page and call the following function that is inside the control:
$
public String checkQuestions()
{
if (questions != null)
{
foreach (Question question in questions)
{
options = question.readOptions();
int i = 0;
foreach (Option option in options)
{
testLabel.Text = option.Checked.ToString(); // test purposes only
}
}
}
return errors;
}
However once i select a radiobutton and click on the submit button the Checked value will always turn out false for all of the options.
Basically it is losing its checked value after a Postback and i am just stuck in trying to solve it.
Would appreciate it if anyone could point me in the right direction.
At a first glance, there are two things I'd check. Firstly, make sure you're implementing IPostBackDataHandler. this requires you to implement two methods, LoadPostData and RaisePostDataChangedEvent. At my first guess, the first one is probably the source of your problem.
Handling postback manually
LoadPostData takes a string postDataKey and a NameValueCollection postCollection and returns a bool indicating whether or not the value has changed as a result of the postback. You don't need to implement this the way .Net originally intends, for example I created a control that held several radio buttons (that for reasons that aren't important here couldn't simply be a RadioButtonList control) and so made sure they were all named by a property string GroupName and inspected the postCollection for that GroupName:
public bool LoadPostData(string postDataKey,
System.Collections.Specialized.NameValueCollection postCollection)
{
bool oldValue = _isChecked;
postCollection = HttpContext.Current.Request.Form; // See note below
_isChecked = (postCollection[this.GroupName] == this.Text);
return oldValue == _isChecked;
}
You'll notice that I'm redefining the postCollection here; this is because postCollection only contains a subset of the HttpRequest.Form corresponding to what ASP.Net thinks your control should care about. As you're also building a composite control here, you probably want to do the same.
Don't worry if this doesn't work first time round; it's worth stepping through what gets passed into this method in debug mode (or outputting things to the HttpContext.Trace, which I often find easier) to see why your code isn't quite what you need.
A quick caveat
One last thing: LoadPostData is only called if the posted form contains a field with a name which matches the UniqueID of your control. As your control is a composite control, you might want to cowboy this slightly, like so:
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
writer.WriteBeginTag("input");
writer.WriteAttribute("type", "hidden");
writer.WriteAttribute("name", this.UniqueID);
writer.WriteAttribute("value", "post");
writer.Write(" />");
}
It's a dirty hack, but it'll work ;o)
Handling viewstate manually
If handling the postback manually doesn't solve your problem, it might be that you need to mess with the viewstate of your control. Don't worry, this is nowhere near as scary as it seems, provided you follow a few simple rules.
To handle your viewstate manually, you just need to override two methods called, obviously enough, LoadViewState and SaveViewState. The first takes an object of viewstate to inflate and the other returns that same object structure. If you make your SaveViewState override return something containing the structure you need to save all the important properties that need persisting, then you just inflate it again in your LoadViewState method.
Here's where the first of the cunning tricks comes up. There are certain datatypes that you should use for saving viewstate and you should never use any other type (because other types are stored really inefficiently). The types that will probably be most useful to you are System.Web.UI.Pair, System.Web.UI.Triplet and our old friends System.Collections.ArrayList and System.Collections.Hashtable. Pairs and Triplets simply store two or three values of type object; ArrayLists are effectively a List<object>.
I'd guess that, in your circumstance, you probably want to store either (1) an ArrayList of boolean flags, storing the "checkedness" of your radiobuttons or (2) an ArrayList of strings or ints, storing the IDs or index of the checked radiobuttons.
In the control I mentioned earlier, I just needed to store the checkedness and the Text property, so my LoadViewState and SaveViewState methods looked like this:
protected override void LoadViewState(object savedState)
{
Pair state = savedState as Pair;
if (state != null)
{
_isChecked = state.First as Nullable<bool> ?? false;
this.Text = state.Second as string;
}
}
protected override object SaveViewState()
{
return new Pair(_isChecked, this.Text);
}
Again, if this doesn't work first time, you almost certainly want to step through the code or throw things into the Trace. Importantly, you probably want to avoid throwing Exceptions from these methods, in case your viewstate is corrupt or non-existent or something.
Further reading on viewstate
There are a couple of very useful articles I keep bookmarked for when I'm messing with viewstate. The first one explains about why you should only store certain types in the viewstate (like using ArrayList and Hashtable, rather than List<T> and Dictionary<TKey, TValue>) and the second is a good in-depth explanation of how all this viewstate stuff actually works.
Don't let the BinaryFormatter get at it!
Truly understanding ViewState
I hope all this helps resolve your problem.
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
}