MVC/ASP.NET: Client side validation not working - asp.net-mvc

EDIT: Consider this whole question replaced by this one:
ASP.NET/MVC: Knockout-binding preventing client-side validation from being performed?
Working in ASP.NET/MVC, I’m having great trouble getting the (unobtrusive or even non-unobtrusive) client side validation to work. (Yes again, but this time for different reasons as it appears.)
NB: The EDITS towards the bottom of the post are important, esp. EDITS 2 and 3.
Problem is, client side validation does absolutely nothing (see below), even though all ingredients seem to be in place. I’ve read through quite a few questions and answers here on Stack Overflow, and it seems everything is done correctly in my project, but still it doesn’t work. What am I missing?
In my Web.config file (the one in the root folder, not the one in the View folder), I’ve explicitly enabled the client side validation:
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
And all the relevant Javascript files are there, in the right order and loading correctly (and I’ve made no changes to them obviously). I’ve included them in bundles, in BundleConfig:
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate.js", "~/Scripts/jquery.validate.unobtrusive.js"));
I add these bundles in my View (well actually in the shared _Layout.cshtml parent view):
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/bootstrap")
#Scripts.Render("~/bundles/knockout")
And in the generated source code for the View these scripts (and a few others) appear as follows:
Which, as far as I can tell, is correct. (I also use the jQuery as well as knockout extensively in other places in the same View.) Also, no loading errors in the browser console.
Then in my ViewModel, I have this annotated property Email (among others):
public class RegisterViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
// some other properties…
}
And this is the corresponding code in my View:
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Email)
</div>
</div>
Which generates the following source code (click to enlarge):
Which also seems correct, as far as I can tell.
But then when I type something that’s evidently not a valid email-address in the input field, and make the field lose focus (by jumping to the next field), NO ERROR MESSAGE appears. Neither in the summary, nor the specific error message for the email field itself. As seen here:
(The little red square is the .field-validation-valid element that should contain the error message, but doesn't. For testing purposes I had decorated this element with a red border.)
Also, when I press the submit button, the input fields are simply submitted to the server action method (which then correctly determines that the inputs are not valid). But in fact, with client side validation enabled, the submit shouldn’t happen unless client side validation succeeds. But well, that’s basically the whole issue: client side validation simply doesn’t happen, despite the correct HTML being generated (presumably!).
EDIT 1:
And here is the HTML/Razor for the whole form:
#model Treinen2.Models.RegisterViewModel
#{
ViewBag.Title = "Register";
}
#using (Html.BeginForm("Register", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Email)
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Password, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.ConfirmPassword, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.ConfirmPassword, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Register" />
</div>
</div>
}
This is in a shared View called Register.cshtml, which -- depending on certain conditions -- gets displayed by calling #Html.Partial("Register") from the home view Index.cshtml. [I'm kind of trying to build a single page API application, as an exercise, so everything is included in the homepage (Index), and all navigation happens client side (with the obvious exception of the submit of the "Register" button itself, which gets sent to the server Action method, at least for now). And with obviously only one part ('page') of Index.cshtml being displayed at any one time, for which I use knockout binding.]
EDIT 2:
OK, I've noticed the following: If I put the same form in Index.cshtml, and also add the same model to that Index view, then client-side validation works perfectly. It's only on the partial view that it fails to work. Which suggests that I could simply stop using the partial view, and instead simply include its content on Index.cshtml, as tested. On the other hand, I still don't understand WHY using the partial view for the register form wouldn't work too. (With this new information, I may have to ask the question anew in a different form, but don't have the time right now...) [/EDIT 2]
EDIT 3:
Seems I'm edging closer to understanding the root cause of the problem. Because now I have the validation working with the form on the Index view... BUT it stops working as soon as I put the whole form inside a DIV-element that is bound by a Knockout attribute data-bind="If: ....." So that seems to be the essence of the problem: the interaction between client-side validation and Knockout binding. The Knockout binding, which in and of itself works fine, seems to prevent the validation from being performed. Although I still don't understand why that should be the case. [/EDIT 3]
So, what am I missing? Any constructive suggestions appreciated, will check back in a few hours.

Related

MVC5 Validation Errors in Razor View

I am using MVC5 and having problem displaying the validation errors of an object both in the Validation Summary section and the individual validation messages for each control.
Lets put aside client validation for the moment although we have ENABLED IT in the web config and included the js files.
If a model that is invalid is passed to a view that has in place a Validation Summary (setting excludePropertyErrors to false) and for each control there is a #Html.ValidationMessageFor(model => model.Summary, "", new { #class = "text-danger" }), shoudn't all these display the Validation errors in the object when the page loads.
We checked the object and the framwork knows it is invlaid (ModelState.IsValid is definitely false) and the errors collection contains several validation errors
(System.Data.Entity.Validation.DbValidationError) but none of them show up neither in the ValidationSummary or the ValidationMessage for the individual controls when the page loads.
Currently I am getting he validation errors manually by context.Entry(prop).GetValidationResult().ValidationErrors.ToList(); and passing it to the Viewbag and iterate over them in the view to display them. Seems crazy!
P.S. The main View is composed of several partial views in which the controls are and the Vaidationsummary is in the Main containing view.
public async Task<ActionResult> GetProduct(id)
{
var product= await context.Products.FindAsync(id);
return View(product);
}
As I mentioned , there are NO VALIDATION MESSAGES ANYWHERE. If we turn off client side validation the input control html is
<input class="form-control text-box single-line valid" id="Price" name="Price" style="font-weight:bold" type="text" value="" aria-invalid="false">
As you can see the value is empty BUT it says it is valid even though the field is a required field marked so via DataAnnotations and the Model is INVALID and includes validation error that Price field is required!
Here is the code:
<div class="form-group">
#Html.LabelFor(m => m.Price, new { #class = "col-sm-3 control-label" })
<div class="col-sm-5">
#Html.EditorFor(model => model.Price, new { htmlAttributes = new { #class = "form-control", style = "font-weight:bold" } })
#Html.ValidationMessageFor(model => model.Price, "", new { #class = "text-danger" })
</div>
</div>
And this is the generated html with client side validation enabled :
<input class="form-control text-box single-line" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Price" name="Price" style="font-weight:bold" type="text" value="">
Would greatly appreciate any assistance.

Fixings Cross Site Scripting (Reflected) in ASP.Net MVC

I have been using the Zed Attack Proxy (ZAP) to test a new application being developed. The App is ASP.NET MVC4 based using the standard HTML helpers where ever possible.
ZAP has identified the following alert:
Cross Site Scripting (Reflected)
GET: localhost:65227/CashReceipt?SearchText=javascript%3Aalert%281%29%3B
On this page we have a list of receipts and a search box whereby a user can search by receipt number.
When this page is called using the link above, the following Razor builds the relevant part of the page:
#using (Html.BeginForm("Index", "CashReceipt", FormMethod.Get, new { #class = "form-inline", #role = "form" }))
{
<div class="form-group">
<label class="hidden-label" for="SearchText">Search For</label>
#Html.TextBoxFor(m => m.SearchText, new { #class = "form-control input-lg", #placeholder = "Receipt Number" })
</div>
<input type="submit" value="Search" class="btn btn-primary btn-lg" />
}
the HTML generated is:
<input class="form-control input-lg" id="SearchText" name="SearchText" placeholder="Receipt Number" type="text" value="javascript:alert(1);" />
The page rendered appears as:
This does not result in an actual alert box being displayed within the browser, just the text is reflected back.
Is this an XSS issue that needs to be resolved? If so, how?
No it is not an XSS issue since the javascript alert is not executed. Razor Html helpers properly encode and decode text to stop this from happening by default.

Client Side Validation for Hidden Input in ASP.NET MVC

I'm still a bit novice to the ASP.NET MVC architecture. I have an Edit page for data, which includes a hidden input. After testing my page, the 'Save' button wasn't doing anything and after some research learned it was a client-side validation issue.
After commenting the following line in the page:
#*#Html.HiddenFor(model => model.ID)*#
(where ID is a GUID), the page validated and posted.
From what I recall, the scaffolding put this code into my view. I just need to know how to fix this so that the ID field gets sent back properly to the controller and wanted to know why it wasn't validating.
Here is my View's code:
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<div class="object_basics">
#Html.HiddenFor(model => model.ID)
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Have you tried to add the validation message for the ID ?
#Html.ValidationMessageFor(model => model.ID)
Client side validation for hidden fields not working, because jQuery validation ignore all hidden tags.
You must define HiddenRequiredValidator class to achieve your goal.
You can read a solution to solve this problem Here
In view, update from:
#using (Html.BeginForm())
To
#using (Html.BeginForm(new{ID = model.ID}))
Remove the hidden element [#Html.HiddenFor(model => model.ID)].
In your controller, update the action properties like below
public ActionResult YourActionName(string ID, string Title)
Hopefully, this answers your question.
Cheers,
Danny

How can I programmatically trigger client side validation set up by a Razor view?

I have a little Ajax application where I use Razor views to initially generated HTML form segments that I later read and write from with knockout.js. Although I am doing no non-Ajax action requests, I use Razor to generate the HTML so I enjoy automatic generation of jQuery Validation attributes. E.g. in my single page, I render a hidden form like this:
<section id="person-detail">
#Html.Action("EditPartial", "Person")
</section>
The EditPartial action returns a partial view that looks a lot like this:
#using (Html.BeginForm())
{
<fieldset>
#Html.HiddenFor(model => model.Id, new { data_bind = "value: id" })
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.FirstName, new { data_bind = "value: firstName" })
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<p>
Update
Delete
</p>
</fieldset>
}
Because I'm never actually posting the form, and due to some unknowns, despite all properties on my Person model being marked with the Required attribute, I see no sign of client side validation. What must I do to trigger this validation when my save button is clicked?
suppose your form has a class 'main':
$('form').submit(function() {
var $form = $('form.main');
$form.valid();
});

ASP.NET MVC3 - displaying "updated" model values for summary display before form submission

I have a view named AddEditModule that is used, believe it or not, for Adding or Editing a module. The workflow is kind of a wizard using navigation buttons that hide/show div's.
I've got a ViewModel called AddEditModuleModel (say that 10 times fast). In steps 1 & 2 I'm displaying my fields using various EditorFor's. In step 3, I'd like to use DisplayFor's to display a Summary of the current values of my textboxes (what's been updated in the View, not what was passed in in the model).
In my Silverlight days, I'd simply have two-way binding between my 'Step1.FirstName' TextBox and a ViewModel property. In my Summary, I could simply display a TextBlock that was also bound to my ViewModel property, or I could use Element Binding to bind my TextBlock.Text proeprty to my Step1.FirstName.Text property.
I know I can't do that in MVC3, but I'm not sure how to solve this. I thought about just ajax posting the updated module and returning a new partial view called ModuleSummary, or something similar, but that seemed kinda hacky (and not entirely sure if that would mess up my file upload on the page).
Is there something I'm missing?
[Edit - sample code]
Scenario:
I'm editing a model which originally has a title of "My Module". Obviously on initial load, my DisplayFor model.title is going to be set to "My Module". Let's assume, on step 1, I change the title to "My New Module Title". What I'd like to know is if there's a way to "refresh" my model when I click the button to display Summary to display my new title.
#model CEAcademy.AddEditModuleModel
#using (Html.BeginForm("AddModule", "Module", FormMethod.Post, new { enctype = "multipart/form-data" })) {
#Html.ValidationSummary(false)
<fieldset>
<legend></legend>
<div id="step1">
<div class="editor-label">
#Html.LabelFor(model => model.title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.title)
#Html.ValidationMessageFor(model => model.title)
</div>
</div>
<div id="summary">
<div class="display-label">
#Html.LabelFor(model => model.title)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.title)
</div>
</div>
<input type="button" id="showSummary" value="Step 2: View Summary" />
</fieldset>
}
Someone just asked a similar question
Display form data before final submission (confirmation view)
I'll ask you the same thing I asked that person. Do you need to go to the server? Is there some extra validation you need to do before displaying the summary?
If not, then you can "easily" do this client side. Use javascript (jQuery or some other lib) to display the summary and at the end then POST the data.

Resources