ASP.NET MVC optional field being treated as required - asp.net-mvc

I have this field that for some reason when I click on submit, gets a validation message that the field is required.
[DisplayName("Total Budget:")]
public double Budget { get; set; }
#Html.EditorFor(model => model.account.Budget)
#Html.ValidationMessageFor(model => model.account.Budget)
public class Account
{
[DisplayName("Total Budget:")]
public double Budget { get; set; } //dropdown
}

The built-in DefaultModelBinder in MVC will perform required and data type validation on value types like int, DateTime, decimal, etc. This will happen even if you don't explicitly specify validation using someting like [Required].
In order to make this optional, you will have to define it as nullable:
public double? Budget { get; set; }

You have to add the following line in the application_start (global.asax)
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
Source: Unrequired property keeps getting data-val-required attribute

double is a value type. Value types always contain a value, even if you did not set one. That value is the default value for it's type (in this case 0.0). All value types are treated as required by the framework. The only way around this is to create a custom model binder, but that will not prevent the model from containing the default value (because there is no way to say that it wasn't entered).
So even if you create a custom binder, when you process your model, you won't be able to tell if someone entered 0 or whether that was just the default value.
Thus, the only real solution is to change your view model to use a nullable type, such as Nullable<double> (shorthand is double?).

You probably change Budget from a double to double?
You probably can try adding this attribute to the controller
BindExclude([Bind(Exclude="Budget")]) as well

Use Nullable or ? after attribute name.

Use [NotMapped] annotation , this removes the required validation in the flow you also use own display attributes

I have just encountered the problem with a project migrated to .Net 6.0, suddenly some fields started to be required even if there's no data annotation for it.
For example, in
public class LoginModel
{
[BindProperty]
public InputModel Input { get; set; }
[TempData]
public string ErrorMessage { get; set; }
...
}
I got the error : "The ErrorMessage field is required", which have of course no sense at all.
The project has <Nullable>enable</Nullable> feature enabled, it seem to cause this.
Simply rewrite property to
public string? ErrorMessage { get; set; }
To fix this (note the question mark)

You may also use:
services.AddControllers(options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);

Related

IgnoreDataMember attribute is skipping json object properties during **DE**serialization

According to the docs, the IgnoreDataMember attribute is only supposed to be considered during serialization.
From what I'm seeing, however, MVC model binding is using it during *de*serialization of json as well.
Consider the following class:
public class Tax
{
public Tax() { }
public int ID { get; set; }
[Required]
[Range(1, int.MaxValue)]
[IgnoreDataMember]
public int PropertyId { get; set; }
}
If POST/PUT the following json string to an action method:
{"Position":0,"Description":"State sales tax","Rate":5,"RateIsPercent":true,"PropertyId":1912}
I get the following validation error:
{
"Message": "The request is invalid.",
"ModelState": {
"newTax.PropertyId": [
"The field PropertyId must be between 1 and 2147483647."
]
}
}
Both the [Range(1, int.MaxValue)] and [Required] attributes are invalid.
If I remove the [IgnoreDataMember] attribute, everything works fine.
Is there a different attribute that can be used which will tell MVC binding not to ignore the property during deserialization?
This only happens when posting a json string. If I post a name/value string, everthing works fine.
The answer has to do with the behavior of Json.net. That's what the model binding is using and it's checking IgnoreDataMember for both serialization and deserialization making it useless for me (since I want to only use it for serialization).
The JsonIgnore attribute works exactly the same way.
Given that, I pulled all the ignore attributes off my properties and switched to using json.net's conditional serialization methods.
So basically add this for the above PropertyId field:
public bool ShouldSerializePropertyId() { return false; }
That allows deserialization to come in but blocks serialization from going out.

MVC Why is this dropdown mandatory?

I have this dropdown in my view (actually I have many of these in a loop)
#Html.DropDownListFor(m => m.SelectedAttributeValueIds[i], Model.AttributeValuesList[Convert.ToInt32(type.Value)], "Select a value")
The relevant parts of the model are
public IDictionary<int, List<SelectListItem>> AttributeValuesList { get; set; }
public List<int> SelectedAttributeValueIds { get; set; }
The dropdowns above contains the correct list of values. If I select one of the values and submit then the value selected is correctly posted and correctly saved into the SelectedAttributeValueIds list.
Now the problem is that if I do not select a value from one or more of these dropdowns my ModelState.IsValid is false in my post action method. Looking at the error list, the reason is that
"a value is required"
Why are the dropdowns mandatory? I'd like them to be optional.
Any ideas?
Thanks,
Sachin
Maybe it is because you use [Required] attribute in Model, if not you can change the property type to nullable one :
public List<int?> SelectedAttributeValueIds { get; set; }
This is because the SelectedAttributeValueIds property is a list of ints that have an implicit value. If you want it to have no value, change the type to a nullable int using List<int?>.
If you really want to leave it as int you can set DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes to false in your Global.asax I'd recommend using the int? however.

ASP.NET MVC 2 "value" in IsValid override in DataAnnotation attribute passed is null, when incorrect date is submitted

This is my first question here on stack overflow.
i need help on a problem i encountered during an ASP.NET MVC2 project i am currently working on.
I should note that I'm relatively new to MVC design, so pls bear my ignorance.
Here goes :
I have a regular form on which various details about a person are shown. One of them is "Date of Birth". My view is like this
<div class="form-items">
<%: Html.Label("DateOfBirth", "Date of Birth:") %>
<%: Html.EditorFor(m => m.DateOfBirth) %>
<%: Html.ValidationMessageFor(m => m.DateOfBirth) %>
</div>
I'm using an editor template i found, to show only the date correctly :
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.DateTime?>"%>
<%= Html.TextBox("", (Model.HasValue ? Model.Value.ToShortDateString() : string.Empty))%>
I used LinqToSql designer to create my model from an sql database. In order to do some validation i made a partial class Person to extend the one created by the designer (under the same namespace) :
[MetadataType(typeof(IPerson))]
public partial class Person : IPerson
{ //To create buddy class }
public interface IPerson
{
[Required(ErrorMessage="Please enter a name")]
string Name { get; set; }
[Required(ErrorMessage="Please enter a surname")]
string Surname { get; set; }
[Birthday]
DateTime? DateOfBirth { get; set; }
[Email(ErrorMessage="Please enter a valid email")]
string Email { get; set; }
}
I want to make sure that a correct date is entered. So i created a custom DataAnnotation attribute in order to validate the date :
public class BirthdayAttribute : ValidationAttribute
{
private const string _errorMessage = "Please enter a valid date";
public BirthdayAttribute() : base(_errorMessage) { }
public override bool IsValid(object value)
{
if (value == null)
{
return true;
}
DateTime temp;
bool result = DateTime.TryParse(value.ToString(), out temp);
return result;
}
}
Well, my problem is this. Once i enter an incorrect date in the DateOfBirth field then no custom message is displayed even if use the attribute like [Birthday(ErrorMessage=".....")]. The message displayed is the one returned from the db ie "The value '32/4/1967' is not valid for DateOfBirth.". I tried to enter some break points around the code, and found out that the "value" in attribute is always null when the date is incorrect, but always gets a value if the date is in correct format. The same ( value == null) is passed also in the code generated by the designer.
This thing is driving me nuts. Please can anyone help me deal with this?
Also if someone can tell me where exactly is the point of entry from the view to the database. Is it related to the model binder? because i wanted to check exactly what value is passed once i press the "submit" button.
Thank you.
Generally speaking all validation stuff is work after binder binded values. As you can understand it's not possible to bind dateTime value from string like "asdvfvk". So, when binder encounters with such an error it adds it to the ModelState (take a look at ModelState["DateOfBirth"].Errors[0].ErrorMessage), and binds default value. Default value for DateTime? is null, so that's why you always get it in IsValid method. It's normal.
So as you can see validation for date has sence if you whant to check for example if it's bigger then some other date. If input string is incorrect no further verification have sence.
What can you do?
First straightforward way - you can correct your action like this
[HttpPost]
public ActionResult About(Person person, string dateOfBirth) {
var birthdayAttribute = new BirthdayAttribute();
if( !birthdayAttribute.IsValid(dateOfBirth)) {
ModelState["DateOfBirth"].Errors.Clear();
ModelState.AddModelError("DateOfBirth", birthdayAttribute.ErrorMessage);
}
.......
}
As you can see there is string dateOfBirth, so binder have no problems with binding string value. But this will not make your users happy.
The better way - ensure that string will be in correct format with client Javascript. Actualy people use date picker controls for dates and feel themselves good.
In addition take a look here http://forums.asp.net/t/1512140.aspx
Especialy Brad Wilson's answer.

Integer validation in asp.net mvc

I am using server side validation like
public IEnumerable<RuleViolation> GetRuleViolations()
{
if (String.IsNullOrEmpty(Name))
yield return new RuleViolation("Name is Required", "Name");
if (Price == 0)
yield return new RuleViolation("Price is Required", "Price");
yield break;
}
When I left Price as blank, Then It takes 0 as a value.
So I check it with 0.
In my Database Price cannot be null; and I am using LINQ-to-SQL class.
Now my problem is when I left Price blank it gives me two messages.e.g.
A value is required.
Price is Required.
So How do I put custom validation without showing first error message?
Relpy to comment
I am reffering book code of Professional Asp.net MVC 1.0 here.
HTML pages of Book are Here.
usefull page.
public class RuleViolation
{
public string ErrorMessage { get; private set; }
public string PropertyName { get; private set; }
public RuleViolation(string errorMessage)
{
ErrorMessage = errorMessage;
}
public RuleViolation(string errorMessage, string propertyName)
{
ErrorMessage= errorMessage;
PropertyName = propertyName;
}
}
I think you get the first message "A value is required" automatically from the framework because your Price property is a value type, which can never be null.
So when you post a blank field, the framework will usually try to assign null to this property, which is not possible in this case.
If you change the type to nullable:
public double? Price { get; set; }
That particular message should disappear. Then you could change your validation to:
if (Price == null)
yield return new RuleViolation("Price is required", "Price");
The fact that the database field does not allow nulls should not interfere with your viewmodels.
To make what Thomas Eyde wrote above work (without messing with the code), you can...
Open the corresponding .dbml file
Click the "Price" property
In the Visual Studio Properties window, change the Nullable value from False to True
Save the file!
You can now go into your class and add the if statement and VS should not complain.
That's because the Default Model Binder adds that error. You can write your own model binder for that particular object and work directly with the form collection to get more control over validation.

ASP.NET MVC: DataAnnotations - Show an error message indicating that a field must be numeric

There appears to be something of a hole in the way DataAnnotations works in that a user entering in some text into a field that will go into an int will never reach the DataAnnotations code. It kicks off a model binding error and displays the error to the user "The value 'a' is not valid for the XXXX field."
Anyway, it's all very nice that it automatically handles this situation, but I actually want to display an error message indicating the problem eg. "The value 'a' is not numeric. Please enter in a numeric value for the XXXX field".
I have tried the solutions set out How to replace the default ModelState error message in Asp.net MVC 2? and ASP.NET MVC - Custom validation message for value types, but I can't get them to work.
It appears that my resource file is not being read at all, since here (http://msdn.microsoft.com/en-us/library/system.web.mvc.defaultmodelbinder.resourceclasskey.aspx) it states "If the property is set to an invalid class key (such as a resource file that does not exist), MVC throws an exception." and even if I change the line to DefaultModelBinder.ResourceClassKey = "asdfasdhfk" there is no exception.
Anyone have any ideas?
EDIT: Here is some code. All of it is working minus my Messages.resx file's messages are not being used. The code for Messages.resx is auto generated so I won't include it.
So entering "a" into ProcessOrder results in a generic message rather than what I have entered into Messages.resx for PropertyValueInvalid (and InvalidPropertyValue for good measure).
Application_Start method
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.DefaultBinder = new Microsoft.Web.Mvc.DataAnnotations.DataAnnotationsModelBinder(); //set dataanooations to be used
DefaultModelBinder.ResourceClassKey = "Messages"; //set data annotations to look in messages.resx for the default messages
ValidationExtensions.ResourceClassKey = "Messages";
}
Entity Class
[MetadataType(typeof(GLMetaData))]
public partial class GL
{
}
public class GLMetaData
{
public int TransRefId { get; set; }
[DisplayName("Process Order")]
public int? ProcessOrder { get; set; }
[DisplayName("Trans Type")]
[StringLength(50)]
public string TransType { get; set; }
[StringLength(100)]
public string Description { get; set; }
[DisplayName("GL Code")]
[StringLength(20)]
public string GLCode { get; set; }
[DisplayName("Agents Credit No")]
[StringLength(50)]
public string AgentsCreditNo { get; set; }
[Required]
public bool Active { get; set; }
}
Controller Action:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(GL glToBeUpdated)
{
try
{
if (!ModelState.IsValid)
return View(glToBeUpdated);
//set auto properties
glToBeUpdated.UpdateDate = DateTime.Now;
glToBeUpdated.UpdateUser = this.CurrentUser;
glDataLayer.update(glToBeUpdated);
glDataLayer.submitChanges();
return RedirectToAction("Index");
}
catch
{
glDataLayer.abortChanges();
throw;
}
}
What I did to combat a similar issue was to clear the model state, validate against ModelState["XXXX"].Value.AttemptedValue instead of against the nulled value caused by an trying to put an invalid value into the Model's property, populating the error messages and resetting the Model values.
That way I can have the error messages I want and if necessary offer more than one ("a value is required" or "the value must be numeric").
I have battled this for most of the day on MVC4 RC. No matter what i set
DefaultModelBinder.ResourceClassKey
to it never seemed to work. It also never threw an exception when I assigned junk.
This is what I was using to assign the value (to no avail):
DefaultModelBinder.ResourceClassKey = typeof(App_GlobalResources.ValidationMessages).Name;
In the end I decided to tackle this error message on the client side and override the data attribute that jQuery uses to display the message.
#Html.TextBoxFor(m => m.Amount, new Dictionary<string,object>(){{"data-val-number","Invalid Number"}})
this is working how I need it to.
Ironically this works too:
#Html.TextBoxFor(m => m.Amount, new Dictionary<string, object>() {{ "data-val-number", HttpContext.GetGlobalResourceObject("ValidationMessages", "PropertyValueInvalid") } })
Here I have taken Contact number field as string but with Range Attribute so can provide numeric validatioin to use if from your Resource file .
[Required(ErrorMessageResourceType = typeof(Global), ErrorMessageResourceName = "ContactNumberRequired")]
[Range(0, int.MaxValue, ErrorMessageResourceType = typeof(Global), ErrorMessageResourceName = "ValidContactNumber")]
[Display(Name = "Contact Number")]
public string ContactNumber { get; set; }
So now here provided ErrorMessageResourceName as key . You can customize and use it also in Multi Language

Resources