How would you validate a checkbox in ASP.Net MVC 2? - asp.net

Using MVC2, I have a simple ViewModel that contains a bool field that is rendered on the view as a checkbox. I would like to validate that the user checked the box. The [Required] attribute on my ViewModel doesn't seem to do the trick. I believe this is because the unchecked checkbox form field is not actually transmitted back during the POST, and therefore the validation doesn't run on it.
Is there a standard way to handle checkbox "required" validation in MVC2? or do I have to write a custom validator for it? I suspect the custom validator won't get executed either for the reason mentioned above. Am I stuck checking for it explicitly in my controller? That seems messy...
Any guidance would be appreciated.
Scott
EDIT FOR CLARITY: As pointed out in comments below, this is a "agree to our terms" type of checkbox, and therefore "not checked" is a valid answer, so I'm really looking for an "is checked" validation.

a custom validator is the way to go. I'll post my code which I used to validate that the user accepts the terms ...
public class BooleanRequiredToBeTrueAttribute : RequiredAttribute
{
public override bool IsValid(object value)
{
return value != null && (bool)value;
}
}

I usually use:
[RegularExpression("true")]

If you didn't want to create your own custom validator and still wanted to use existing attributes in the model you could use:
[Range(typeof(bool), "true", "true", ErrorMessage="You must accept the terms and conditions.")]
This ensures that the range of the boolean value is between true and true. However, whilst this method will work, I would still prefer to use a custom validator in this scenario. I just thought i'd mention this as an alternative option.

I too am looking for a way to have the model binder correctly handle check boxes with Boolean values. In the mean time I'm using this in the Actions:
Object.Property = !String.IsNullOrEmpty(Request.Form["NAME"]);
Maybe this will be of some use to you.

Related

ASP.NET Web Pages 2 Select Value Validation

I figure this must be so simple and I'm missing something really obvious. I want to validate the selected value of a select input on an ASP.NET Web Pages 2 form using the built in validators but it doesn't look possible so far.
For example:
Validation.Add("my-select", Validator.ValueEquals("Some Value"));
Where Validator.ValueEquals would compare the selected value to the supplied parameter value "Some Value". I realize I could do:
if(Request["my-select"] != "Some Value") {
Validation.AddFormError("Invalid option selected");
}
But then I don't have the error message associated with the field and it will only appear if I'm rendering the validation summary at the top of the form.
What am I missing?
I've cracked the code! Unfortunately the solution is outside of the scope of the built in Validation and Validators static methods but I was able to achieve what I needed by using the following in place of the using the Validation class.
if(Request["my-select"] != "Some Value") {
ModelState.AddError("my-select", "Invalid option selected");
}
Then check if the ModelState is valid when checking Validation.IsValid():
if(ModelState.IsValid && Validation.IsValid()) {
// More codes...
}
It's kind of cool that ModelState is available but it really seems clunky that this isn't handled by the Validation and Validator classes.
You could use the EqualsTo validator and compare the supplied value to a hidden field value, or if you are worried that users might tamper with the hidden field value, you can write your own custom validator. I've blogged how to do that: http://www.mikesdotnetting.com/Article/195/ASP.NET-Web-Pages-Creating-Custom-Validators

Model Binding and Validation Errors

I am using asp.net MVC3 and I am very new to this technology.
My models are designed in such a way that the properties will throw validation errors if the data is invalid. In this case, the properties are not set with invalid data.
When I redisplay my editing-view, validation error messages are shown; however the values that the user previously entered are gone because the model that it is bound to only contains the old-valid data.
For example, say I had a Person class and the Name property cannot be a null or empty string otherwise it throws a validation exception and prevents the property from being set. Now say the user removes the value from the Name property and tries to save the Person from the web. A validation exception will be thrown and handled properly to add the error to the ModelState so that it is displayed on the screen; however the old value for the Name is redisplayed since the invalid, empty string never made it into the property.
I do not know how to solve this problem and any advice on the issue would be greatly appreciated.
My advise is allow invalid data but use validation attributes. You wont save invalid entities so there is no problem and this is the standard approach these days. If you don't want do that, there is no easy solution. Most simple solution would be using the info from Request.Form
You should implement IValidatableObject to performe this kind of validation at server side.
From MSDN IValidatableObject Interface:
Provides a way for an object to be invalidated.
Theres an exemple here Using IValidatableObject Custom Validation, also from MSDN.
The solution to this problem was to create a ViewModel that allowed invalid data to be entered into this. This solution also simplified my ModelBinder classes because it took on most of the work.

Getting the actual field data from a Linq Expression

I'm working on an ASP.NET MVC3 application and I annotated my model with an attribute that specifies what roles can change specific fields for any possible status the model is in. Take this as an example:
public class Model
{
[RoleLimiter(
new[]{Role.Admin, Role.BasicUser, Role.Validator}, // for draft
new[]{Role.Admin, Role.BasicUser, Role.Validator}, // for awaiting validation
new[]{Role.Admin})] // for published etc
public string Subject {get;set;}
}
It looks a bit messy, sure, but it's very easy to change if needed. Now once I have this, it's easy to check for each field the current status and then get the list of roles that can change it. If the current role isn't in it, I'll add a disabled class to the control.
What I wanted to do next is to make a HtmlHelper extension that has the same syntax as the normal EditorFor (or even a straight-forward TextBoxFor), but does this extra check and automatically adds the attribute behind the scenes, but I'm stuck on getting the field info from the expression, ie:
How do you get from
HtmlHelper.TextBoxWithRoleLimitationsFor(x=>x.Subject);
to the attribute attached to x.Subject?
You fetch the LambdaExpression.Body and check whether it's a MemberExpression. You can then get the Member of the MemberExpression and get the custom attributes from that.

Extending ASP.NET validators

I want to extend the asp.net validators such that I can make one validator dependent on another. The situation I have is that we have to validate a date in a textbox. Normally I would just use a combination of a RequiredFieldValidator (to ensure the date is provided), CompareValidator (to ensure the date is a date) and finally a RangeValidator (to ensure the date is within the required limit).
The problem with this is that the validators do not depend on each other, so as a result the user would see possibly all three messages at once for each validator when really all we want them to see is the most relevant message, i.e. if they entered "abc" in the date text box it would not be appropriate to show them the message saying the date was not in the valid range (even though technically I suppose this is true).
Currently to provide this kind of functionality we use a CustomValidator and just put all three validations within the server validate event handler and change the error message programmatically depending on what validation failed.
I would like to standardize this a bit more as it happens quite a bit in this application, I figure if I can make the validators dependent on each other this will solve the problem and also allow us to make use of the client side validation rather than having to do a postback especially to handle the custom validation.
The idea is that if one validator is dependent on another if that "master" is valid then the depended will perform its normal validation (EvaluateIsValid()) otherwise if the master validator is not valid then the other dependent validators will be valid.
I have come up with the following solution by inheriting from the various validator controls that already have been provided in the framework.
public class RequiredFieldDependentValidator : RequiredFieldValidator
{
[Description("The validation control to depend on for determining if validation should occur")]
public string ValidationControlToDependOn
{
get
{
object obj = ViewState["ValidationControlToDependOn"];
if (obj != null) return (string) obj;
return null;
}
set
{
Control control = FindControl(value);
if (control is IValidator)
ViewState["ValidationControlToDependOn"] = value;
else
throw new HttpException("ValidationControlToDependOn is not a validation control");
}
}
protected override bool EvaluateIsValid()
{
IValidator validationControlToDependOn = FindControl(ValidationControlToDependOn) as IValidator;
if(validationControlToDependOn != null)
{
return !validationControlToDependOn.IsValid || base.EvaluateIsValid();
}
return base.EvaluateIsValid();
}
Currently I have just coded it for the RequiredFieldValidator, ideally I would like to provide this functionality for all of the validators but I cannot see a way to do this without copying the above code into a similar class for each individual type of validator I want to provide this functionality for thus if there are any problems I'm going to have to go back and change this code on each validator type individually.
Is there a way I can "centralise" this code and have it easily used in the validators without having to write the entire validators from scratch just so I can change the class they inherit from further down the line.
Cheers,
You could override the Validate method in you page base. To add the validation dependency information in the page you can implement a not rendered control:
<my:ValidationDependency TargetControl="RegExp1" Dependency="Required1" />
You might want to look into a WebControlAdapter.
Basically allows you to override certain methods of webcontrols (conditionally for some browsers if need, but here can be for all).
In your case, you would want to override the EvaluateIsValid method and check if the control has any dependency on a 'parent' validator.
As an example, a TextBox adapter we recently created to render a 'maxlength' attribute to the control.
Public Class TextBoxAdapter
Inherits WebControlAdapter
Private ReadOnly Property TextBoxControl() As TextBox
Get
Return DirectCast(MyBase.Control, TextBox)
End Get
End Property
Protected Overrides Sub RenderBeginTag(ByVal writer As System.Web.UI.HtmlTextWriter)
If TextBoxControl.TextMode = TextBoxMode.MultiLine AndAlso TextBoxControl.MaxLength > 0 Then
writer.AddAttribute("maxlength", TextBoxControl.MaxLength.ToString)
End If
MyBase.RenderBeginTag(writer)
End Sub
End Class
To use it, just create a .browser file in your App_Browsers directory and setup the adapter there:
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.WebControls.TextBox"
adapterType="TextBoxAdapter" />
</controlAdapters>
</browser>
</browsers>
The only complication that still remains in your case is how to store the dependent validator in order for the EvaluateIsValid to have access to this directory. You might consider a non-rendered control like Onof suggested or else Viewstate/Cookie/other storage mechanism.
you can have ValidationControlToDependOn property as of type List and add the validators into the list. So we can assume that the validator added later depends upon the validator added before it.
so your protected override bool EvaluateIsValid()
will change somewhat
foreach(IValidator validator in ValidationControlToDependOn)
{
return !validator.IsValid;
}
I'm looking into control extenders which seems like it could be promising but I cannot find many examples of doing anything but AJAX stuff with it.

DataAnnotations Automatic Handling of int is Causing a Roadblock

Summary: DataAnnotation's automatic handling of an "int?" is making me rethink using them at all.
Maybe I'm missing something and an easy fix but I can't get DataAnnotations to cooperate. I have a public property with my own custom validation attribute:
[MustBeNumeric(ErrorMessage = "Must be a number")]
public int? Weight { get; set; }
The point of the custom validation attribute is do a quick check to see if the input is numeric and display an appropriate error message. The problem is that when DataAnnotations tries to bind a string to the int? is automatically doesn't validate and displays a "The value 'asdf' is not valid for Weight."
For the life of me I can't get DataAnnotations to stop handling that so I can take care of it in my custom attribute.
This seems like it would be a popular scenario (to validate that the input in numeric) and I'm guessing there's an easy solution but I didn't find it anywhere.
Here's a workaround (as I wouldn't really call this a solution). Add a Messages.resx file inside the App_GlobalResources folder of your web application. Add the following resource inside:
Key: PropertyValueInvalid
Value: {0} Must be a number
In the Application_Start method of Global.asax add the following:
DefaultModelBinder.ResourceClassKey = "Messages";

Resources