MVC3 Required validation, choose value for empty - asp.net-mvc-3

I have a hidden field which is bound to a int Id in the model, it has a required attribute and some fancy ajax code to set the id client side, the problem is that zero should be acounted as empty. Now the validation will succeed even if no Id has been selected, bow can I set which value should be counted as empty? I hope i do not need to create a custom validator for it.
Thanks

It doesn't maker sense to add required attribute to a non nullable type such as Int32. Value types are always required. You could use a nullable integer instead:
[Required]
public int? SomeProperty { get; set; }

Related

Why model validation is not working

I have following Model class that is used during the Web API Post. As you can see Id field is annotated as Required.
public class Model
{
[Required]
public Guid Id { get; set; }
}
The Post for API is as follows
[HttpPost]
public IActionResult Post([FromBody]Model value)
{
if (!ModelState.IsValid)
return BadRequest();
Model newModel = new Model() { Id = value.Id };
return Ok(newModel);
}
On a sunny day, this is what I see. All good
enter image description here
On a rainy day, when Id is not provided, I get following.
enter image description here
Given that in the second example, a Required field is not provided, shouldn't a BadRequest is returned rather than a 200 with invalid id guid with 00000000-0000-0000-0000-000000000000?
Using the Required annotation
In the Web API Docs, your issue is known as 'under-posting'.
The issue is that Guid has a default value, so when no value is provided, it is initialized with the default value... which then satisfies the Required constraint.
To prevent this, counter-intuitively you make the Guid nullable using Guid?.
Then if the value is not provided, the deserializer will set the value to null, which will cause the Required constraint to be violated.
If the value is provided, it will be set, and all will be well.
See https://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api for more details, there is an example of a similar issue for a decimal property.
The key distinction to understand is that Guid.Empty is really a valid Guid. The only way to distinguish between the user providing a Guid (which is empty) and not providing one at all is to make it nullable, so null = not provided, and Empty = the user provided the empty Guid.
Using a Custom Annotation
If you really don't want to make your Guid nullable, you need to consider what would you do for a 'normal' value type, e.g. an integer. Rather than making it required, you'd use a Range attribute and specify that it must be > 0.
Similarly for Guids, you'd ideally have an attribute that would simply test that it is != Guid.Empty
See https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation#custom-validation for guidance on creating a custom validation atribute.

DropDownList Client Side Validation is validating when it should not be. (MVC3, Razor)

I am still learning MVC3 and Razor, so this is perhaps a simple question.
On a view I have a DropDownList whose sole purpose is to help filter (via AJAX) a second drop down list:
#Html.DropDownList("Segments", "-- select segment --")
There is a Segments property of the ViewModel that is defined as:
public IEnumerable<SelectListItem> Segments { get; set; }
There is JavaScript that handles the change event for this DropDownList and populates another DropDownList with appropriate values. That other DropDownList is defined like this:
#Html.DropDownListFor(m => m.fafhProdRecId, Enumerable.Empty<SelectListItem>(), "-- select product recommendation --")
This all works fine until I submit. When I submit, I get a validation error on the Segments drop down list!
Now -- there should be absolutely NO validation on the segments DropDownList -- there shouldn't be any client side validation on EITHER drop down list, for that matter.
But when I try to submit, I get the validation error message back:
The value '1' is invalid.
I have no idea why this is happening.
I have no idea how to decorate the Segments property to say that it is NOT required.
I have no idea how to tell the unobtrusive javascript validator that it is, in fact, being quite obtrusive.
In your ViewModel class add [Bind(Exclude = "Segments")]
From: Using Data Annotations for Model Validation
make sure that your Model has fafhProdRecId as nullable, I imagine it's declared as:
public int fafhProdRecId { get; set; }
change this to:
public int? fafhProdRecId { get; set; }
hopefully, that should resolve the issue as this effectively makes the model field nullable (assuming the db field IS nullable too of course).

.NET MVC3 Remove Currency Symbol and Commas

In my model I have the following property:
[DataType(DataType.Currency)]
public decimal? Budget { get; set; }
When the user enters in $1,200.34, I need that value to be valid and strip out the currency symbol and comma.
In my controller I'm doing:
if (race.Budget != null)
{
race.Budget.ToString().Replace("$", "").Replace(",", "");
}
The problem is that client validation doesn't pass the value for budget into the controller. I get a value of null. How can I override the client validation so that I can strip out the currency symbol and comma?
Thank you in advance for the help.
UPDATE
So here's the strange thing. Let's say I want to bypass client validation all together. I added #{ Html.EnableClientValidation(false); } to my view and it's still sending a null value for Budget when I submit to the controller.
This isn't a client side validation problem. Your model has a field of type decimal? The model binder will try to bind a value of $123,456.78 into that and fail, so the value will be null. Here's one way to get around this:
Change your model to have a string property that masks your decimal:
public decimal? Budget { get; set; }
public string BudgetText {
get {
return Budget.HasValue ? Budget.ToString("$") : string.Empty;
}
set {
// parse "value" and try to put it into Budget
}
}
Then, just bind to BudgetText from your View. Validate it as a string with a regular expression that accepts only money input. It'll probably be the same regex you can use for your BudgetText's set method
So you can probably hook in some JQuery to pre-process the form field to strip the characters off you don't want (prior to form submission to the server). This is probably the quickest, dirtiest approach.
For something reusable, have a look into custom client validation adapters. The links aren't spot on, but should get you in the right direction. For Brad's screencast, I believe the relevant parts are fairly early on.
Check out the support for jQuery localization
cliente validation using jQuery validate for currency fields
also there is a plugin for currency validation as well
http://code.google.com/p/jquery-formatcurrency/
check out this recent post as well for a $ in binding
.NET MVC 3 Custom Decimal? Model Binder

IValidatableObject and Nullable value types

I have a struct that implements IValidatableObject, which I use for properties on a view model. The validation works fine with non-nullable properties, but if add a property of type Nullable<MyStruct> the IValidatableObject.Validate method is never called for that property, even if it has a value.
Is there any way that I trigger the validation on my nullable properties too, or is IValidatableObject not intended to be used with value types?
Thanks
Additional information:
I wanted to be able to specify units when entering data in my form, e.g. 10m, 100km, 1cm etc. I also wanted to validate that the entered data was within range and of a correct format. My struct converts the string with potentially different units (100cm/100m/1km) into a decimal property which always has the same unit (1/100/1000) and vice-versa.
I used IValidatableObject for validation because the validation will always be the same for any instance of MyStruct - I didn't want to add an attribute each time it is used.
My model would look something like this:
public class MyModel
{
public MyStruct Ab {get; set;}
public MyStruct? Cd {get; set;}
}
My view is a strongly typed view using the model, which renders my struct as a text box using a display template. When the form is posted, I have a custom model binder to convert the entered string back to my struct.
My controller action looks like:
public ActionResult MyAction(MyModel model)
{
//do stuff
}
The model is bound ok for properties of type MyStruct and Nullable<MyStruct>.
It seems that this is not possible.
I dug into the MVC source. In System.Web.Mvc.DataAnnotationsModelValidatorProvider there is the following code:
// Produce a validator if the type supports IValidatableObject
if (typeof(IValidatableObject).IsAssignableFrom(metadata.ModelType)) {
//stuff
}
According to this rejected bug report, Nullable<T> cannot be assigned to an interface that T implements:
"In short, a "DateTime?" value can be unboxed to a DateTime or an IFormattable value. But it cannot be assigned to a DateTime or IFormattable location."
Thus no validators are returned.
Looks like I will have to do this another way.

Globally localize validation

I'm using System.ComponeneModel.DataAnnotations attributes such as Required and StringLength. Is it possible to localize its error messages globally?
I know I can do this
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Resources.Validation))]
But doing this everywhere I use required attribute would be just insane. Also I'd like to avoid stuff like:
public class LocalizedRequiredAttribute : RequiredAttribute {
public LocalizedRequiredAttribute()
: base() {
ErrorMessageResourceName = "Required";
ErrorMessageResourceType = typeof(Resources.Validation);
}
}
(but if there isn't any other way, I'll settle for this)
AFAIK you need either a custom attribute or specify the ErrorMessageResourceName and ErrorMessageResourceType properties. There is another possibility detailed here:
Create a global resource class in
App_GlobalResources, and set
DefaultModelBinder.ResourceClassKey to
the name of this class (for example,
if you made "Messages.resx", then set
ResourceClassKey to "Messages").
There are two strings you can override
in MVC 2:
The string value for
"PropertyValueInvalid" is used when
the data the user entered isn't
compatible with the data type (for
example, typing in "abc" for an
integer field). The default message
for this is: "The value '{0}' is not
valid for {1}."
The string value for
"PropertyValueRequired" is used when
the user did not enter any data for a
field which is not nullable (for
example, an integer field). The
default message for this is: "A value
is required."
It's important to note
in the second case that, if you have
the
DataAnnotationsModelValidatorProvider
in your validator providers list
(which it is by default), then you
will never see this second message.
This provider sees non-optional fields
and adds an implied [Required]
attribute to them so that their
messages will be consistent with other
fields with explicit [Required]
attributes and to ensure that you get
client-side validation for required
fields.
For MVC3 see DataAnnotationsResources. It's "RequiredAttribute_ValidationError" and more.
You may solve it by installing .NET Framework language pack(s).
See also

Resources