Asp.net mvc client side validation

I have been exploring client side validation features in ASP.net MVC after reading a ScottGU blog post on this subject. It is fairly easy to use the System.Componentmodel.DataAnnotations attributes as follows:

[Required(ErrorMessage = "You must specify a reason")] public string ReasonText { get; set; } 

... but what happens if you need something a little more complicated. What if you have an Address class with the PostalCode and CountryCode fields. You would like to check the postal code for a different regular expression for each country. [0-9] {5} works in the USA, but for Canada you need another one.

I circumvented this by flipping my own ValidationService class, which uses the controller's ModelState property and validates it accordingly. This works fine on the server side, but does not work with the new client-side validation.

In Webforms, I would use javascript-emitting controls, such as RequiredFieldValidator or CompareValidator, for easy use, and then use CustomValidator for complex rules. This way, I have all of my validation logic in one place, and I get the advantage of quick javascript validation for simple things (in 90% of cases), while I still get server-side validation security as a backstop .

What will be the equivalent approach in MVC?

+7
source share
5 answers

Edit: It is assumed that you are using MVC 3. Unfortunately, my code is in VB.NET, since I have to use it at work.

So that everything is fine with a new unobtrusive check, you need to do a few things. I passed through them a couple of weeks ago.

First, create your own attribute class that inherits from ValidationAttribute . A simple RequiredIf attribute class is below:

 Imports System.ComponentModel Imports System.ComponentModel.DataAnnotations <AttributeUsage(AttributeTargets.Field Or AttributeTargets.Property, AllowMultiple:=False, Inherited:=False)> _ Public NotInheritable Class RequiredIfAttribute Inherits ValidationAttribute Private Const _defaultErrorMessage As String = "'{0}' is required." Private ReadOnly _dependentProperty As String Private ReadOnly _targetValues As Object() Public Sub New(dependentProperty As String, targetValues As Object()) MyBase.New(_defaultErrorMessage) _dependentProperty = dependentProperty _targetValues = targetValues End Sub Public Sub New(dependentProperty As String, targetValues As Object(), errorMessage As String) MyBase.New(errorMessage) _dependentProperty = dependentProperty _targetValues = targetValues End Sub Public ReadOnly Property DependentProperty() As String Get Return _dependentProperty End Get End Property Public ReadOnly Property TargetValues() As Object() Get Return _targetValues End Get End Property Public Overrides Function FormatErrorMessage(name As String) As String Return String.Format(Globalization.CultureInfo.CurrentUICulture, ErrorMessageString, name) End Function Protected Overrides Function IsValid(value As Object, context As ValidationContext) As ValidationResult ' find the other property we need to compare with using reflection Dim propertyValue = context.ObjectType.GetProperty(DependentProperty).GetValue(context.ObjectInstance, Nothing).ToString() Dim match = TargetValues.SingleOrDefault(Function(t) t.ToString().ToLower() = propertyValue.ToLower()) If match IsNot Nothing AndAlso value Is Nothing Then Return New ValidationResult(FormatErrorMessage(context.DisplayName)) End If Return Nothing End Function End Class 

Then you need to implement the validator class. This class is responsible for ensuring that MVC knows the client validation rules necessary for an unobtrusive validation library to work.

 Public Class RequiredIfValidator Inherits DataAnnotationsModelValidator(Of RequiredIfAttribute) Public Sub New(metaData As ModelMetadata, context As ControllerContext, attribute As RequiredIfAttribute) MyBase.New(metaData, context, attribute) End Sub Public Overrides Function GetClientValidationRules() As IEnumerable(Of ModelClientValidationRule) Dim rule As New ModelClientValidationRule() With {.ErrorMessage = ErrorMessage, .ValidationType = "requiredif"} rule.ValidationParameters("dependentproperty") = Attribute.DependentProperty.Replace("."c, HtmlHelper.IdAttributeDotReplacement) Dim first As Boolean = True Dim arrayString As New StringBuilder() For Each param In Attribute.TargetValues If first Then first = False Else arrayString.Append(",") End If arrayString.Append(param.ToString()) Next rule.ValidationParameters("targetvalues") = arrayString.ToString() Return New ModelClientValidationRule() {rule} End Function End Class 

Now you can register everything in the Global.asax application launch method:

 DataAnnotationsModelValidatorProvider.RegisterAdapter(GetType(RequiredIfAttribute), GetType(RequiredIfValidator)) 

This gives you 90% of the way. Now you just need to tell the jQuery validate and MS unobtrusive level of validation how to read your new attributes:

 /// <reference path="jquery-1.4.1-vsdoc.js" /> /// <reference path="jquery.validate-vsdoc.js" /> /* javascript for custom unobtrusive validation ==================================================== */ (function ($) { // this adds the custom "requiredif" validator to the jQuery validate plugin $.validator.addMethod('requiredif', function (value, element, params) { // the "value" variable must not be empty if the dependent value matches // one of the target values var dependentVal = $('#' + params['dependentProperty']).val().trim().toLowerCase(); var targetValues = params['targetValues'].split(','); // loop through all target values for (i = 0; i < targetValues.length; i++) { if (dependentVal == targetValues[i].toLowerCase()) { return $.trim(value).length > 0; } } return true; }, 'not used'); // this tells the MS unobtrusive validation layer how to read the // HTML 5 attributes that are output for the custom "requiredif" validator $.validator.unobtrusive.adapters.add('requiredif', ['dependentProperty', 'targetValues'], function (options) { options.rules['requiredif'] = options.params; if (options.message) { options.messages['requiredif'] = options.message; } }); } (jQuery)); 

Hope this helps, it was a real pain to work.

+7
source

ScottGu tweeted this morning as Pluralsight has a free MVC 3 workout for the next 48 hours. They have a video showing how to perform such a special check. The corresponding videos are in the “Models in ASP.NET MVC 3.0” section, in particular, “Custom Validation Attributes” and “Self-tuning Models”.

+3
source

I just saw something about the IValidatableObject interface in MVC 3, and I will try.

+1
source

Derive your own validation attribute from the ValidationAttribute and apply the appropriate logic. In MVC 2, in order to perform a property check based on the value of another property, this must be done inside the Validator, which you register for use with the special validation attribute, using (provided that you use DataAnnotationsModelValidatorProvider )

 DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(ValidationAttribute), typeof(ValidationValidator)); 

because in the validation attribute you only have access to the value of the property to which the attribute is bound, and not to the model.

See the MVC FoolProof Validation to see how this approach is implemented.

+1
source

I think the solution to your problem is System.ComponentModel.DataAnnotations in MVC

For complex logic, you can implement your own logic. It is very easy. Look for settings at this link: http://msdn.microsoft.com/en-us/library/cc668224.aspx

For the main thing, you get a View Binded with a Model Class and add an attribute on top of the properties ... How

 public class CustomerSearchDE { [StringLength(2, ErrorMessageResourceType = typeof(Translation), ErrorMessageResourceName = MessageConstants.conCompanyNumberMaxLength)] public string CompanyNumber { get; set; } } 

Show Strongly enter this class

0
source

All Articles