Reputation: 5717
I need to use Range Validator in my asp.net mvc 4 project. In view model I added:
[Range(0, int.MaxValue, ErrorMessage = "The Region field is required.")]
public int Region { get; set; }
And in controller i checked it by ModelState.IsValid
.
The problem is ModelState don't accept 0
as a properly value - it's strange because I set range from 0
to max int
, so I thought that 0
belong to collection (like in MVC 5 if I remember). Am I wrong or it's just a bug? Any others value is reading properly (-1
is not accepting and 1001
is ok).
UPDATE 1
(Like you see in above pictures I don't anything with my model before I not check if model is valid).
Register method:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
//I was never here! Always ModelState.IsValid returns false
}
// If we got this far, something failed, redisplay form
ViewBag.Regions = _database.Department.ToList();
return View(model);
}
Full RegisterViewModel class:
public class RegisterModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
[Required]
[Display(Name = "Role")]
public int Role { get; set; }
[Range(0, int.MaxValue, ErrorMessage = "The Region field is required.")]
[Display(Name = "Region")]
public int Region { get; set; }
}
Register view:
<fieldset>
<legend>Registration Form</legend>
<ol>
<li>
@Html.LabelFor(m => m.UserName)
@Html.TextBoxFor(m => m.UserName)
</li>
<li>
@Html.LabelFor(m => m.Password)
@Html.PasswordFor(m => m.Password)
</li>
<li>
@Html.LabelFor(m => m.ConfirmPassword)
@Html.PasswordFor(m => m.ConfirmPassword)
</li>
<li>
@Html.LabelFor(m => m.Role)
<select id="Role" name="Role" data-val-required="The Role field is required." data-val="true">
<option value="">Choose role for user</option>
<option value="1">Administrator</option>
<option value="2">Inspector</option>
</select>
</li>
<li id="region-section">
@Html.LabelFor(m => m.Region)
<select id="Region" name="Region" data-val-required="The Region field is required." data-val="true">
<option value="" selected>Choose region</option>
@foreach (var item in ViewBag.Regions)
{
<option value="@item.Id">@item.Name</option>
}
</select>
</li>
</ol>
<input type="submit" value="Register" />
</fieldset>
UPDATE 2
According to @pilotcam advice I have used ValidateModel()
function. In debug mode I got HResult: -2146233079
- I was trying convert it into System Error Code (-2146233079 & 0xFFFF = 5385
) but is not a part of System Error Codes list.
Upvotes: 0
Views: 1971
Reputation: 5717
Finnaly I've found answer. The problem was in type of my field (public int Region { get; set; }
). If I don't set anything, mvc trying set null to Region
but int isn't nullable so in controller during debugging I still getting 0
instead null
which was ambiguous.
I didn't have [Required]
attribute, but not-nullable type added it automatically (with error name "The X field is required" ... yeah, just like my custom error message in [Range]
attribute).
The solution is change:
public int Region { get; set; }
to:
public int? Region { get; set; }
... in viewmodel.
Upvotes: 1
Reputation: 21191
Rather than using ViewBag, I would suggest adding a Regions property to your Register class, like so:
public class RegisterModel
{
// ... existing code
public SelectList Regions { get; set; }
}
This requires some updates to your action methods:
// your GET action
public ActionResult Register()
{
var model = new RegisterModel();
model.Regions = new SelectList(_database.Department, "Id", "Name", model.Region);
return View(model);
}
And then, finally, update your view:
<li id="region-section">
@Html.LabelFor(m => m.Region)
@Html.DropDownListFor(m => m.Region, Model.Regions, "Select one...")
</li>
This seems to be more consistent than using ViewBag and writing the <select>
element by hand, in my experience.
If you still are getting odd results from validation, I'd recommend installing Glimpse and checking out the model binding tab, which will show how your posted values are being mapped.
Upvotes: 1