MVC CheckBoxFor causing unobtrusive validation to be bypassed - asp.net-mvc

I have a form containing a number of controls - nothing fancy:
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
<fieldset>
<legend>EmployeeViewModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Employee.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Employee.Title)
etc.....
UPDATE
My ViewModel:
public class EmployeeCreateViewModel
{
public EmployeeCreateModel Employee { get; set; }
..etc
My Employee model:
public class EmployeeCreateModel
{
[Required]
public string Title { get; set; }
[DisplayName("Job Title")]
[Required]
public string JobTitle { get; set; }
public bool Active { get; set; }
...etc
The Problem - I am using unobtrusive validation which works fine UNTIL I add a checkbox to the form. Regardless of the checkbox state, the form is submitted, bypassing client-side validation and errors are caught by the server-side validation. This is my checkbox:
<div class="editor-label">
#Html.LabelFor(model => model.Employee.Active)
</div>
<div class="editor-field">
#Html.CheckBoxFor(model => model.Employee.Active)
</div>
The checkbox model property is not a required field, so it doesn't need to be validated and I can see that it has a valid True/False value when it reaches the controller method.
Why is this happening, and how can I fix it?

First, open javascript console (e.g., chrome inspector panel) and see if you are getting Uncaught TypeError: Object [object Object] has no method 'live' error from jquery.unobtrusive-ajax.js.
If you are seeing this error, you are probably using jquery 1.9.x or higher. If you check "Preserve log upon navigation" (chrome), you can see an error saying "Uncaught SyntaxError: Unexpected token u".
To solve this problem, include jquery migrate 1.2.x after jquery 1.9.x.
<script src="/Scripts/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/jquery-migrate-1.2.1.js"></script>
For details, see this post.

Related

Default values and validation in ASP RazorPage

My PageModel has a single BindProperty like ?Query=, whose length should not exceed 1000. However, I also want this string to always be defined; on initial page load (or if a blank form is submitted), I want to use the default value "*" instead of null or "":
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel.DataAnnotations;
namespace RazorTestApp.Pages;
public class IndexModel : PageModel
{
[BindProperty(SupportsGet = true)]
[StringLength(1000)]
[Required(AllowEmptyStrings = false)]
public string Query { get; set; } = "*";
public void OnGet()
{
}
}
I have an equally simple View:
#page
#model IndexModel
<div class="text-center">
<form method="get">
#Html.EditorForModel()
<div>
<input type="submit" />
</div>
</form>
</div>
I am having 2 issues with this:
Load page with no query string (initial load): the input box correctly displays "*", but I also get a validation error "The Query field is required".
Load page with ?Query= (submit with empty query): the input box does not show the default "*" (shows empty string), and I get the same validation error "The Query field is required".
I am obviously not doing this correctly. How can I set a default value for Query to be used whenever it is empty/not provided, and have it play nicely with validation?
I tried to test the validations on my side.
Below is my model:
[BindProperty(SupportsGet = true), Required, StringLength(1000)]
public string Rating { get; set; } = "*";
View:
<div class="form-group">
<label asp-for="Movie.Rating" class="control-label"></label>
<input asp-for="Movie.Rating" class="form-control" />
<span asp-validation-for="Movie.Rating" class="text-danger"></span>
</div>
Output:
On my side, I could see that * is added to the input field and if I remove it and submit the form then I get the validation message.
For testing purposes, I would suggest you make a test with the <form method="post">. If the issue persists then creating a new model and view and trying to test it separately may help to narrow down the issue.

ASP.NET MVC 5 model validation for non-nullable types (Int32)

I'm working on an ASP.NET MVC 5 application and the project owner is concerned about "under-posting" issues caused by validating non-nullable types (as mentioned in http://bradwilson.typepad.com/blog/2010/01/input-validation-vs-model-validation-in-aspnet-mvc.html and http://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api).
I created a test case to replicate this issue in ASP.NET MVC 5 but without luck.
Model:
public class ContactModel
{
[Required]
public Int32 data1 { get; set; }
public Int32 data2 { get; set; }
}
View:
<div class="form-group">
#Html.LabelFor(model => model.data1)
<div>
#Html.EditorFor(model => model.data1)
</div>
</div>
<div>
#Html.LabelFor(model => model.data2)
<div>
#Html.EditorFor(model => model.data2)
</div>
</div>
Controller:
public ActionResult Index(Models.ContactModel contact)
{
if (ModelState.IsValid)
{
Response.Write("modelstate is valid<br>");
return View();
}
else
{
Response.Write("modelstate is invalid<br>");
return View();
}
}
It seems that when data1 and data2 are null in the post, their values in the model (contact) will be 0. However, ModelState.IsValid will also be false (instead of true as shown in the two articles).
What I have:
What the second article showed:
I couldn't find any information regarding changes on how model validation works in ASP.NET MVC, so I'm guessing I did something wrong with my test case. Any thought and suggestion are appreciated.
The reason your ModelState is false is because the post is providing form values from each property in your model. Essentially the Model binding system is checking the validity of both data1 and data2 fields as you have #Html.EditorFor helpers explicitly written for both properties in your view (so no underposting is actually going on).
I did successfully replicate the under-posting concerns from the articles. Simply remove one of the EditorFor helpers in your view, so you're actually underposting. With both helpers present, there's no underposting going on. So the view looks like this now (note I added the validation helper for both properties to get feedback in the view on what's going on):
View:
<div class="form-group">
#Html.LabelFor(model => model.data1)
<div>
#Html.EditorFor(model => model.data1)
#Html.ValidationMessageFor(model => model.data1)
#Html.ValidationMessageFor(model => model.data2)
</div>
</div>
Make sure to leave the #Html.EditorFor helper completely off for the data2 property. Now fill in zero in the form field (you'll only one form field in the view of course now), and post to your action.
ModelState will come back as true in this scenario, even though only one form field is being posted. Not a good result if someone does underpost! So here's the (slightly modified) original model class where underposting issues will occur in the case a form field is left off of your form (note the Required attributes don't make any difference in this situation as both properties are value types):
//You could add the Required attribute or not, doesn't matter at this point.
//The concern here is that the Modelstate will still come back as Valid
//in the case of a form field being left off of your form (or someone underposts).
//So to replicate underposting issues, make sure to comment or delete
//at least one Html.EditorFor helper in the view.
//[Required] Underposting will occur regardless if this is marked required or not,
//so be careful if someone does underpost your form.
public Int32 data1 { get; set; }
//[Required]
public Int32 data2 { get; set; }
Now the solution if you want to solve the underposting issue:
Simply mark both properties as required and make them nullable as mentioned in the articles you provided, like so:
[Required]
public Int32? data1 { get; set; }
[Required]
public Int32? data2 { get; set; }
Now when the view is posted with a missing #Html.EditorFor helper or a missing form field, the ModelState Validation will come back as false, and you're protected from underposting issues.

How to validate against a Model's metadata through a custom ViewModel?

I'm working on a webapp using ASP MVC. I'm building a page to edit a user's data (model USER, view ModifyUser).
I have a model with validations in this manner:
[MetadataType(typeof(USERS_Metadata))]
public partial class USER
{
public class USERS_Metadata
{
[Required(ErrorMessage = "FALTA NOMBRE")]
[StringLength(30, ErrorMessage = "Nombre entre 3 y 30 caracteres", MinimumLength = 3)]
[RegularExpression(#"^[a-zA-Z''-'\s]{1,40}$", ErrorMessage = "Error en el formato del nombre.")]
public string NAME { get; set; }
I then use a view that automagically validates user inputs:
<div class="editor-label">
<%: Html.LabelFor(model => model.SURNAME) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.SURNAME) %>
<%: Html.ValidationMessageFor(model => model.SURNAME) %>
</div>
The problem is my view is also gonna need to access some other entities with their own models, like USERCATEGORY, which makes using an strongly typed view a bit more uncomfortable.
Aditionally, and may be even more important, I don't want my view to have to deal with, and even knowing about, properties such as the user's session ID, which currently I handle like this (and i hate it):
<%: Html.HiddenFor(model => model.SESSIONID) %>
Unless I'm utterly mistaken, the most sane option is to build a custom ViewModel. I decided to build my ModifyUserViewModel to match those fields in USER I'm gonna need in my view, and add a few fields from the other models... But I have no idea of how to propagate the metadata in USER, that I use for field validation, to the new ViewModel. This metadata is automatically built from the database, and copypasting it would make me feel dead inside, even if it works.
What is the canonical, most maintenable, easiest way to validate from the View like I am currently doing, but with a ViewModel?
Try to build your view model as an aggregate of several domain models:
public class MyViewModel {
public USER User { get; set; }
public USERCATETORY Category { get; set; }
}
See a great article here.

How to use a simple calender in MVC 4 Razor

I am very new on MVC. How can I use a calender? Here is my div
<div class="editor-field">
#Html.EditorFor(model => model.CommunicationTime)
#Html.ValidationMessageFor(model => model.CommunicationTime)
</div>
But it shows only a text box. What should I do?
try to add Data annotations DateType(DateType.Date) within your model
here is a sample :
[Display(Name = "Date of Birthday")]
[DataType(DataType.Date)]
public DateTime DOB { get; set; }
this Should work in Chrome , Firefox , Safari or any browser Supports HTML5
that's because the produced html tags will contain type="Date" in date field

Email validation not working in MVC

In my MVC application, email validation is working perfectly locally but when I m publishing and deploying to server It won't work. I have compared the html source of both local and deployed files and there is no difference. My Razor view mark up is
<li>
<p><strong>Email: </strong>#Model.CurrentEmailAddress <span class="deliverychange" onclick="showHidden('emailchange');">(Change email)</span></p>
<div id="emailchange" class="fullborder" style="display: none;">
<div class="orderrow newemailaddress">
#Html.LabelFor(m => m.UpdatedEmailAddress)
#Html.TextBoxFor(m => m.UpdatedEmailAddress, new { #onkeypress = "showEmailChangeConfirmation();" })
#Html.ValidationMessageFor(m => m.UpdatedEmailAddress)
</div>
<div id="updatedemailkeypress" style="display: none;">
<div class="orderrow checkboxrow emailchangeconfirm">
#Html.LabelFor(m => m.UpdateEmailAddress)
#Html.EnumRadioButtonFor(m => m.UpdateEmailAddress, false)
</div>
</div>
<div class="clear"> </div>
</div>
</li>
and my model is as
[DataType(DataType.EmailAddress)]
[RegularExpression(#"^([\w.-]+)#([\w-]+)((.(\w){2,3})+)$", ErrorMessage = "Email is not valid")]
[Display(Name = "Enter new email address: ")]
public string UpdatedEmailAddress { get; set; }
[Display(Name = "We will use ****")]
public YesNo UpdateEmailAddress { get; set; }
Use the EmailAddress-attribute instead
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.emailaddressattribute%28v=vs.110%29.aspx
Please recheck that form tag is there.
Form validation works actually by validating form valid method.
So, the form is required to be exist.
Hope this helps.
After spending a lot of time on this I found the publish wizard is not copying the jquery.validate-vsdoc.js to the scripts folder. I manually copied this to the server and all started working.
Try to use dataannotationsextensions library, you can download from nuget.
and just add Email attribute to your model like this
using DataAnnotationsExtensions;
[Required]
[DataType(DataType.EmailAddress)]
[Email]
public string UpdatedEmailAddress { get; set; }

Resources