Reputation: 1061
I am having an issue with custom validation in MVC version 5.
I have the following code below as the validator.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace PortalWebsite.Common
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class GreaterThanAttribute : ValidationAttribute, IClientValidatable
{
public string OtherPropertyName { get; private set; }
public bool AllowEquality { get; private set; }
public GreaterThanAttribute(string otherPropertyName, bool allowEquality = true)
{
AllowEquality = allowEquality;
OtherPropertyName = otherPropertyName;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var result = ValidationResult.Success;
var otherValue = validationContext.ObjectType.GetProperty(OtherPropertyName)
.GetValue(validationContext.ObjectInstance, null);
if (value != null)
{
if (value is DateTime)
{
if (otherValue != null)
{
if (otherValue is DateTime)
{
if (!OtherPropertyName.ToLower().Contains("DateTo"))
{
if ((DateTime)value > (DateTime)otherValue)
{
result = new ValidationResult(ErrorMessage);
}
}
else
{
if ((DateTime)value < (DateTime)otherValue)
{
result = new ValidationResult(ErrorMessage);
}
}
if ((DateTime)value == (DateTime)otherValue && !AllowEquality)
{
result = new ValidationResult(ErrorMessage);
}
}
}
}
}
return result;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = ErrorMessage,
ValidationType = "comparedates"
};
rule.ValidationParameters["otherpropertyname"] = OtherPropertyName;
rule.ValidationParameters["allowequality"] = AllowEquality ? "true" : "";
yield return rule;
}
}
}
Then in my view model, I have:
public int Id { get; set; }
public DateTime? NotificationDateTo { get; set; }
[Display(Name = "Notification Date")]
[GreaterThan("NotificationDateTo", ErrorMessage = "Start date cannot be before end date")]
public DateTime? NotificationDateFrom { get; set; }
This code is working, and result from IsValid is getting set correctly. My problem is that the code is not returning back to the calling view. It just carries on as if nothing is invalid.
My view is like this (abridged):
@using (Html.BeginForm("SearchResults", "Claims", new { id = 1 }, FormMethod.Get))
{
<div class="row">
<div class="large-12 columns">
<div class="row">
<div class="small-3 columns">
@Html.LabelFor(m => m.NotificationDateFrom, new { @class = "right inline" })
</div>
<div class="small-4 columns">
@Html.TextBoxFor(model => model.NotificationDateFrom, new { autocomplete = "off", @class = "datePicker" })
<span class="error">@Html.ValidationMessageFor(m => m.NotificationDateFrom)</span>
</div>
<div class="small-1 columns">
and
</div>
<div class="small-4 columns">
@Html.TextBoxFor(model => model.NotificationDateTo, new { autocomplete = "off", @class = "datePicker" })
<span class="error">@Html.ValidationMessageFor(m => m.NotificationDateTo)</span>
</div>
</div>
</div>
</div>
}
Upvotes: 3
Views: 4244
Reputation:
In your POST method, your need to check the ModelState.IsValid
property, and if invalid, return the view which will display the error messages
public ActionResult SearchResults(yourViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
// save and redirect
Side note: Unless client side validation is disabled, you should not be hitting POST method which suggests you have not included the validation scripts associated with your GreaterThanAttribute
. You need to include 2 scripts that add the rules to the validator
$.validator.addMethod(...) {
and
$.validator.unobtrusive.adapters.add(...) {
Unless these are included, there is little point implementing IClientValidatable
in your attribute
Upvotes: 5