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 va开发者_开发百科lue. 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!" />
精彩评论