[英]Custom validation attribute to check for duplicates among my model properties is not firing
I want to add a custom validation attribute to my model to check if any of the answers contain duplicates. 我想为我的模型添加一个自定义验证属性,以检查是否有任何答案包含重复项。 That is, if the user types in the same answer for any of the fields, I want to display an error when they type in a duplicate answer.
也就是说,如果用户为任何字段输入相同的答案,我想在输入重复答案时显示错误。
Here's my model: 这是我的模特:
public class SecurityQuestions
{
public int Question1Id { get; set; }
public int Question2Id { get; set; }
public int Question3Id { get; set; }
public int Question4Id { get; set; }
public int Question5Id { get; set; }
public int Question6Id { get; set; }
[UniqueAnswersOnly]
public string Answer1 { get; set; }
[UniqueAnswersOnly]
public string Answer2 { get; set; }
[UniqueAnswersOnly]
public string Answer3 { get; set; }
[UniqueAnswersOnly]
public string Answer4 { get; set; }
[UniqueAnswersOnly]
public string Answer5 { get; set; }
[UniqueAnswersOnly]
public string Answer6 { get; set; }
}
Here's my attempt at custom attribute: 这是我对自定义属性的尝试:
public class UniqueAnswersOnly: ValidationAttribute, IClientValidatable
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
//Get a list of all properties that are marked with [UniqueAnswersOnly]
var props = validationContext.ObjectInstance.GetType().GetProperties().Where(
prop => Attribute.IsDefined(prop, typeof(UniqueAnswersOnly)));
var values = new HashSet<string>();
//Read the values of all other properties
foreach(var prop in props)
{
var pValue = (string)prop.GetValue(validationContext.ObjectInstance, null);
if (prop.Name!=validationContext.MemberName && !values.Contains(pValue))
{
values.Add(pValue);
}
}
if (values.Contains(value))
{
return new ValidationResult("Duplicate answer", new[] { validationContext.MemberName });
}
return null;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule()
{
ErrorMessage = metadata.DisplayName + " is required!",
ValidationType = "duplicateanswers"
};
yield return rule;
}
}
The problem I'm having now is the the validation is sucessful even though I enter in duplicate answers. 我现在遇到的问题是即使我输入重复的答案,验证也是成功的。 I can still continue to next dialog (I am expecting validation to fail if duplicates are entered).
我仍然可以继续下一个对话框(如果输入重复项,我希望验证失败)。 I think it's because my custom attribute isn't being fired or hit because I added breakpoints but nothing is hit.
我认为这是因为我的自定义属性没有被触发或被击中,因为我添加了断点但没有被击中。
In my controller, I have if(ModelState.IsValid) { //continue to next dialog}
and the model state does return valid. 在我的控制器中,我有
if(ModelState.IsValid) { //continue to next dialog}
并且模型状态确实返回有效。
You could create a custom validation attribute like this: 您可以创建一个自定义验证属性,如下所示:
public class UniqueAnswersOnly : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
//Get a list of all properties that are marked with [UniqueAnswersOnly]
var props = validationContext.ObjectInstance.GetType().GetProperties().Where(
prop => Attribute.IsDefined(prop, typeof(UniqueAnswersOnly)));
var values = new HashSet<string>();
//Read the values of all other properties
foreach(var prop in props)
{
var pValue = (string)prop.GetValue(validationContext.ObjectInstance);
if (prop.Name!=validationContext.MemberName && !values.Contains(pValue))
{
values.Add(pValue);
}
}
if (values.Contains(value))
{
return new ValidationResult("Duplicate answer", new[] { validationContext.MemberName });
}
return null;
}
}
and here is a test case: 这是一个测试用例:
public class SecurityQuestions
{
public int Question1Id { get; set; }
public int Question2Id { get; set; }
public int Question3Id { get; set; }
public int Question4Id { get; set; }
public int Question5Id { get; set; }
public int Question6Id { get; set; }
[UniqueAnswersOnly]
public string Answer1 { get; set; }
[UniqueAnswersOnly]
public string Answer2 { get; set; }
[UniqueAnswersOnly]
public string Answer3 { get; set; }
[UniqueAnswersOnly]
public string Answer4 { get; set; }
[UniqueAnswersOnly]
public string Answer5 { get; set; }
[UniqueAnswersOnly]
public string Answer6 { get; set; }
}
class Program
{
static void Main(string[] args)
{
var questions = new SecurityQuestions();
questions.Answer1 = "Test";
questions.Answer2 = "Test";
questions.Answer3 = "Test3";
questions.Answer4 = "Test4";
questions.Answer5 = "Test5";
questions.Answer6 = "Test6";
var vc = new ValidationContext(questions, null, null);
var results = new List<ValidationResult>();
var validationResult = Validator.TryValidateObject(questions, vc, results, true);
}
}
Edit: 编辑:
I created a default MVC project and added your current code. 我创建了一个默认的MVC项目并添加了您当前的代码。 That validation works just fine.
验证工作得很好。
I added this to the home controller: 我把它添加到家庭控制器:
public ActionResult AskQuestions()
{
var questions = new SecurityQuestions();
return View(questions);
}
[HttpPost]
public ActionResult CheckQuestions(SecurityQuestions questions)
{
if (ModelState.IsValid)
{
return View();
}
else
{
return HttpNotFound();
}
}
And the AskQuestions view looks like this: AskQuestions视图如下所示:
@model WebApplicationValidation.Models.SecurityQuestions
@{
ViewBag.Title = "AskQuestions";
}
<h2>AskQuestions</h2>
@using (Html.BeginForm("CheckQuestions", "Home",FormMethod.Post))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>SecurityQuestions</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.Question1Id, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Question1Id, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Question1Id, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Question2Id, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Question2Id, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Question2Id, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Question3Id, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Question3Id, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Question3Id, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Question4Id, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Question4Id, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Question4Id, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Question5Id, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Question5Id, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Question5Id, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Question6Id, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Question6Id, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Question6Id, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Answer1, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Answer1, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Answer1, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Answer2, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Answer2, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Answer2, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Answer3, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Answer3, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Answer3, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Answer4, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Answer4, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Answer4, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Answer5, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Answer5, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Answer5, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Answer6, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Answer6, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Answer6, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
If I run the app the ModelState.IsValid() is false if I enter two identical answers. 如果我运行应用程序,如果我输入两个相同的答案,则ModelState.IsValid()为false。 And setting a breakpoint in the validation routine shows that it's being run.
在验证例程中设置断点表明它正在运行。
You can implement the IValidatableObject
interface in your Model like below, and use jQuery to take care of the validation on the client side. 您可以在模型中实现
IValidatableObject
接口,如下所示,并使用jQuery来处理客户端的验证。
public class SecurityQuestions : IValidatableObject
{
public int Question1Id { get; set; }
public int Question2Id { get; set; }
public int Question3Id { get; set; }
public int Question4Id { get; set; }
public int Question5Id { get; set; }
public int Question6Id { get; set; }
public string Answer1 { get; set; }
public string Answer2 { get; set; }
public string Answer3 { get; set; }
public string Answer4 { get; set; }
public string Answer5 { get; set; }
public string Answer6 { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var securityAnswers = new List<string>();
securityAnswers.Add(this.Answer1);
securityAnswers.Add(this.Answer2);
securityAnswers.Add(this.Answer3);
securityAnswers.Add(this.Answer4);
securityAnswers.Add(this.Answer5);
securityAnswers.Add(this.Answer6);
bool hasDuplicates = securityAnswers.GroupBy(x => x).Where(g => g.Count() > 1).Any();
if (hasDuplicates)
{
yield return new ValidationResult(
"There are duplicate Answers...");
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.