Asp.net MVC client validation, no client validation with sub-items? - asp.net-mvc

I'm using asp.net mvc 3 for a project and already using the server and client validation on several pages. It works fine. But this time, I've a special case:
Items in the view are bounds to the model and also to some of its properties.
one example:
public class MyModelView{
[Required]
[StringLength(100, MinimumLength = 2)]
public String Name{get;set;}
public DetailsObject Details{get;set;}
}
public class DetailsObject{
[Required]
[StringLength(100, MinimumLength = 2)]
public String PropertyOne{get;set;}
[Required]
[StringLength(100, MinimumLength = 2)]
public String PropertyTwo{get;set;}
}
and in the view I've "bindings on all elements
#Html.TextBoxFor(m=>m.Name)
#Html.TextBoxFor(m=>m.Details.PropertyOne)
#Html.TextBoxFor(m=>m.Details.PropertyTwo)
The problem is that I don't get any client validations. The server validation is still working fine for all properties.
I've the jquery validate unobtrusive included. How do you manage that?

there are several places you should check
web.config should have those lines
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
check the javascripts to be included in right order
<script src="/Scripts/jquery-latest.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
also as a reminder (as I don't see the whole view file) place ValidationMessageFor helpers to see validation errors

Related

DataAnnotations - Validation not happening

validation is working normal on local box, dev site but it is not happening on the staging and production sites. Both client side and server side validation is not happening. Both staging and production are load balanced but use sticky connection due to some other functional requirements.
I have checked the bin folder on all environments and i see the following two dlls there.
DataAnnotationsExtensions.ClientValidation.dll
DataAnnotationsExtensions.dll
On the server side, following should fail but it is not happening.
!TryValidateModel(model) || !ModelState.IsValid
This site use windows authentication.
Web.config
<appSettings file="Configs\AppSettings_LocalHost.config">
<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>
For testing purposes, i am not using bundles at this time. For the bundles, i even tested it with following
<location path="~/Content">
<system.web>
<authorization>
<allow users ="*" />
</authorization>
</system.web>
</location>
<location path="~/bundles">
<system.web>
<authorization>
<allow users ="*" />
</authorization>
</system.web>
</location>
<location path="~/Scripts">
<system.web>
<authorization>
<allow users ="*" />
</authorization>
</system.web>
</location>
And i have the following JS files referenced as well
<script src="/NetSite/Scripts/Core/jquery.validate.min.js?v=1.12" type="text/javascript"></script>
<script src="/NetSite/Scripts/Core/jquery.validate.unobtrusive.min.js?v=1.12" type="text/javascript"></script>
<script src="/NetSite/Scripts/Custom/Validators.js?v=1.12" type="text/javascript"></script>
The app is MVC 5 and all has been added via the NuGet package. I don't have the MVC installed on the server. I have another MVC 5 app on these servers and validation is happening just fine.
And here is the form tag, the second working app uses the same form tag.
using (Html.BeginForm(ActionNames.Index, ControllerNames.Rankings, new { Area = AreaNames.MemberToolsReports }, FormMethod.Post, new { id = "RankingsSearchForm" }))
On the old staging and production boxes, validation was working but then we had MVC 3 installed on it.
Update - Controller Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Project.BusinessEntities;
using Project.Common.Constants;
using Project.MvcBase;
using Project.Resources;
using Project.ServiceInterfaces;
using Project.ViewModels;
using Project.ViewModels.MemberToolReports;
using Microsoft.Practices.Unity;
using Project.Helpers.Helpers;
using Project.Helpers.IO;
namespace Project.Site.Areas.MemberToolsReports.Controllers
{
public class RankingsController : BaseController
{
#region PROPERTIES
[Dependency]
public IGeographyService GeographyServiceInstance { get; set; }
[Dependency]
public IRankingsService RankingsServiceInstance { get; set; }
[Dependency]
public IUtilityService UtilityServiceInstance { get; set; }
#endregion
#region ACTIONS
public ActionResult Index()
{
var states = getting states here
var key = String.Empty;
var search = new RankingSearch { Key = key };
var model = new RankingSearchViewModel { Search = search, StatesList = states };
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(RankingSearchViewModel model)
{
var errorModel = new ContentShowError { IsError = true };
var resultModel = new RankingsSearchResultsViewModel();
try
{
//TODO: remove extra code once data annotations issue is fixed on staging and prod
if (!Request.IsAjaxRequest())
{
errorModel.Message = base.GetDisplayMessage(ProcessingMessagesEnum.ErrorServicingRequest);
}
else if (!TryValidateModel(model) || !ModelState.IsValid)
{
errorModel.Message = base.GetDisplayMessage(ProcessingMessagesEnum.ErrorProcessingRequest);
}
else if (String.IsNullOrWhiteSpace(model.Search.Key) &&
String.IsNullOrWhiteSpace(model.Search.Institution) &&
String.IsNullOrWhiteSpace(model.Search.State))
{
errorModel.Message = base.GetDisplayMessage(ProcessingMessagesEnum.NoCriteriaSpecified);
}
else
{
//default - debug code
errorModel.Message = base.GetDisplayMessage(ProcessingMessagesEnum.ErrorNoDataFound);
var results = RankingsServiceInstance.SearchRanking(model.Search);
if (results != null && results.Count > 0)
{
errorModel.IsError = false;
errorModel.Message = String.Empty;
//update result model
resultModel.Rankings = results;
}
}
}
catch (Exception ex)
{
errorModel.Message = base.GetDisplayMessage(ProcessingMessagesEnum.ErrorProcessingRequest);
base.LogException(ex);
}
ActionResult result = null;
result = errorModel.IsError ? PartialView(ViewNames.ErrorControl, errorModel) : PartialView(ViewNames.SearchResultsControl, resultModel);
return result;
}
#endregion
}
}
Update 2 - HTML Difference
Looks like validation attributes are not even making it to the html, as if the site doesn't even know that we are using validation. Right now, both, dev and staging sites have the same code.
Staging site
<input autofocus="autofocus" class="clearSearchFields" id="Search_Key" maxlength="6" name="Search.Key" size="6" type="text" value="" /><br />
Working dev site
<input autofocus="autofocus" class="clearSearchFields" data-val="true" data-val-length="Key must be 6 characters long" data-val-length-max="6" data-val-length-min="6" data-val-regex="Only alphanumeric (A-Z a-z 0-9) values are allowed" data-val-regex-pattern="[A-Za-z0-9]*" id="Search_Key" maxlength="6" name="Search.Key" size="6" type="text" value="" /><br />
<span class="field-validation-valid" data-valmsg-for="Search.Key" data-valmsg-replace="true"></span>
Since you have had another mvc 5 app on that machine that which runs fine and you don't have MVC installed it would appear that something isn't being deployed correctly. Most likely something there is some assembly needed in the MVC package that you don't have.
Is there a reason you can't install MVC on the server? There are stand alone packages available for that. That should add everything to the GAC that you need.
If you can't install MVC I would look at the bin of your working MVC 5 app. Does it appears to have more .Net assemblies than your new application? If so then someone probably included all the missing MVC assemblies in it. You could try copying all the assemblies over from the working mvc app, just make sure you don't override. That should show you any assembly that you are missing.
Since some of the posters do not read the fully question and comments and try to answer, i am moving my last two comments from the question thread as an answer. My issue is fixed.
I moved the web.config from my local machine over to staging and prod and validation started working. I have checked the old web.config and this new working folder web.config and there are no differences. Even though it is working, i am happy but i am now confused at the same time.
Looks like the ASP.NET temp file was an issue in this case. When i updated the web.config manually, the temp file got updated as well, which fixed the issue for me.

MVC how to validate DateTime field with also client validation

In my View Model I have setup a field with this attributes.
All work fine if the user enter the date and time in the correct format.
An error appear if the User do not insert the DateTime in the right format.
I would like have validation also in the client.
Could you tell me how to do it?
[Required]
[Display(Name = "Start DateTime")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy HH:mm}")]
public System.DateTime DateTimeStart { get; set; }
Getting format exceptions from a property of type DateTime is very annoying issue. It is a fairly common issue when working with validation on DateTime.
DataAnnotaions works on server side and to take their full advantage you need to add ModelState.IsValid() in your controller.
public ActionResult Index(MyViewModel model)
{
if(ModelState.IsValid())
{
// valid data received...
}
else
{
// Invalid data, add model error here and return view...
}
}
If you to make these work on client side then you need to include two additional JavaScript files in your code i.e. jquery.validate.js and jquery.validate.unobtrusive.js along with jQuery core library. By Default all of these files comes in basic MVC project and included in Layout.
It is important to note the order of including these files. jQuery core should always be at the top followed by validation libraries.
jquery.js
jquery.validate.js
jquery.validate.unobtrusive.js
Make sure the validation flags are turned on in web.config file of
MVC project. Go to this file and locate the following and set them
true if they are false.
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
This should setup your validations to work on client side. You can decorate the model property with the RegularExpression.
[Required]
[RegularExpression("^(([0-2]?[0-9]|3[0-1])/([0]?[1-9]|1[0-2])/[1-2]\d{3}) (20|21|22|23|[0-1]?\d{1}):([0-5]?\d{1})$", ErrorMessage = "Invalid date")]
public string DateTimeStart { get; set; }
This will validate the datetime in dd-mm-yyyy hh:mm format.
Besides in this case you can make your property a string type also because regular expression will take care of your date format.
Apart from this, you can also create your custom DataAnnotation.
Firstly, what are you using to allow user to enter a date ?
If you are using Jquery DatePicker, then see this example there is no way the user can enter date in wrong format (except for inspecting the element and changing the textbox value, which can be ignored.)
Sample Code using Jquery Datepicker :
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>jQuery UI Datepicker - Default functionality</title>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.0/themes/base/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.8.3.js"></script>
<script src="http://code.jquery.com/ui/1.10.0/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css" />
<script>
$(function() {
$( "#datepicker" ).datepicker();
});
</script>
</head>
<body>
<p>Date: <input type="text" id="datepicker" /></p>
</body>
</html>
and incase you are not using DatePicker I very strongly recommend you to use it.
Incase you are new to datepicker, you can go through the following listed articles to get started :
Introduction to jquery Date Picker in ASP.NET MVC
jQuery UI. Widgets. Datepicker (Calendar)

mvc foolproof validation client side script not showing until after form submitted

I am using foolproof on a couple question in an MVC 3 for. Specifically I have radio buttons with a textarea, if the radio button 'Yes' is selected, then the textarea can not be empty. I have other validation on some fields, using regular 'Required' attribute and those work fine, but the 'RequiredIfTrue' attributes do not validate on the client side. So if I fill in all the fields so they will validate, then click Yes on a radio but leave the corresponding textarea empty, then submit, the form hits the server instead of validating client side. I also noticed when Viewing the Source in the browser, the 'RequiredIfTrue' attributes are not added to the HTML until after the form is submitted.
I am using a ViewModel for this project, and that seems to be the problem. CUrrently the attributes are on the properties, which are in a model, then I refer to that model in the ViewModel and pass the ViewModel to the View. But if I put the properties directly in the ViewModel, it works correctly. I don't want the properties in hte ViewModel , because wouldn't I then need to add some kind of mapping code to the ViewModel so the properties are associated with the correct model/table?
These are the scripts included in the project:
<link href="#Url.Content("~/Content/mvc.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/jquery-ui-1.8.22.custom.css")" rel="Stylesheet"" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-1.8.2.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery-ui-1.8.22.custom.min.js")" type="text/javascript""></script>
<script src="#Url.Content("~/Scripts/HistoryArrayTables.js")" type="text/javascript""></script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MicrosoftAjax.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MicrosoftMvcAjax.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MicrosoftMvcValidation.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/mvcfoolproof.unobtrusive.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MvcFoolproofJQueryValidation.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MvcFoolproofValidation.min.js")" type="text/javascript"></script>
Here is part of the model:
using Foolproof;
namespace EligibityForm.Models
{
[MetadataType (typeof(HistoryMetadata))]
public partial class History
{
}
public class HistoryMetadata
{
[StringLength(2000)]
[RequiredIfTrue("HasComment", ErrorMessage="Please enter an explanation")]
[Display(Name = "Have you EVER been subject to a lawsuit?")]
public string Comment { get; set; }
public bool HasComment { get; set; }
}
And here is part of the ViewModel:
using Foolproof;
namespace EligibityForm.Models.CompositeModels
{
public class HistoryViewModel
{
public History HistoryModel { get; set; }
Thanks.

MVC 3 building dynamic meta keywords meta description functionality for multi-culture site

I need to create db driven meta keywords/description. I would store these records in a database, xml format i presume; since it would be per culture.
How would i go about doing this?
any feedback, suggestions, help, greatly appreciated.
thanks
What you need to change is just the call to method that returns the keywork/description
You can use Thread.CurrentThread.CurrentUICulture to determine the user culture.
You need to change at web.config to auto change the culture.
Ex.:
(Web.Config)
<globalization uiCulture="auto" culture="auto" />
(Controller)
ViewBag.Description = GetDescription(pageId, Thread.CurrentThread.CurrentUICulture.Name)
(View)
<meta name="description" content="#ViewBag.Description ">
Make a parent interface for all your model objects. and you could have:
public interface IBaseMasterViewDto
{
int PageId { get; set; }
string Title { get; set; }
string MetaKeywords { get; set; }
string MetaDescription { get; set; }
}
Thus in your master view you could use
<%# Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<IBaseMasterViewDto>" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">
<head>
<title><%: Model.Title %></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="keywords" content="<%: Model.MetaKeywords %>" />
<meta name="description" content="<%: Model.MetaDescription %>" />
Hope it helps.
Shane,
I answered a somewhat similar question here on SO a while back. I didn't cover the cultural elements, but fujiy's answer above goes towards that in a way. Also, alexl's interface is a FAR better solution to loose typed viewdata elements (as per my answer in the similar question). anyway, here's what i answered 'on the day' for that question:
MVC and Meta Tags for Search Engine Optimization
1 - Get keywords/description (from your Model) in your controller
2 - Assign them to a Viewbag property
3 - Display the viewbag property in your layout (or view)
OR
Assign your model with keywords/description and give it to your view as a parameter in your controller.
About the culture :
You just have to put it as a parameter in your method controller (and in your route).
After that, you have to give this parameter to your method retrieving keywords/description.

ASP.NET MVC 3 RC 2 client side validation with globalization

My goal is to validate a user input on the client-side, depending on the users' culture.
I have a primitive data-model with the following structure:
public class User
{
public int UserId { get; set; }
[Required]
[StringLength(20,MinimumLength=3)]
public string Name { get; set; }
[Required]
public double Height { get; set; }
}
Furthermore, I want to have client-side validation enabled, checking if it is a valid number. Therefore, I've added the following lines in the <head> section of my _Layout.cshtml.
<script src="#Url.Content("~/Scripts/jQuery-1.4.2.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
Since I want to have the ability to validate the input in another language formats (in this particular context it's German with the decimal number format of 0,75 whereas in the US it would be 0.75), I've added the following lines (jQuery Globalization PlugIn) AFTER the previously mentioned jquery.validate.min.js and jquery.validate.unobtrusive.min.js.
<script src="#Url.Content("~/Scripts/jquery.glob.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/globinfo/jquery.glob.de-de.js")" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$.culture = jQuery.cultures['de-DE'];
$.preferCulture($.culture.name);
});
</script>
In addition, I've added the following line to the web.config in the system.web section just to make sure that the German culture is always selected:
<globalization culture="de-DE" uiCulture="de-DE" />
Now I am experiencing the following behavior:
If I type in 0,1 (note the German 'spelling') in the textbox for the value of "Height", the validation error message The field Height must be a number appears and I'm not able to submit the form.
If I type in 0.1 (English 'spelling'), I can submit the form but the server-side validation returns the following validation error message The value '0.1' is not valid for Height.
So now I am in some kind of dead lock where I can't get out.
Again, my goal is to validate the decimal number input on the client AND server side, based on the users' culture (in this case it's forced to be German). What am I doing wrong?
Any help is highly appreciated! Thank you in advance!
Unfortunately there's a naming conflict between jQuery.validate.format and jQuery.Globalization.format functions. Therefore you'll have to change your code to use the non-jquery Globalization plugin.
I just wrote a blog post about it here.
For you it should look like this:
<script src="#Url.Content("~/Scripts/globalization.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/globinfo/Globalization.de-DE.js")" type="text/javascript"></script>
<script type="text/javascript">
$.validator.methods.number = function (value, element) {
if (!isNaN(Globalization.parseFloat(value))) {
return true;
}
return false;
}
$(document).ready(function () {
$.culture = jQuery.cultures['de-DE'];
$.preferCulture($.culture.name);
Globalization.preferCulture($.culture.name);
});
</script>
That should be enough.
I had to disable the UnobtrusiveJavaScript. The page does not react instantly anymore, but at least it works.
You can disable by default in the Web.Config.
<appSettings>
<add key="enableSimpleMembership" value="false"/>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="false"/>
</appSettings>
And I use the Microsoft scripts for validation:
MicrosoftAjax.js
MicrosoftMvcAjax.js
MicrosoftMvcValidation.js
And also the jquery-1.4.4.min.js & jquery.glob thing, but I think I use them internally. The validation is being done by the MS scripts.

Resources