c# - Custom validation attribute to check for duplicates among my model properties is not firing -
i want add custom validation attribute model check if of answers contain duplicates. is, if user types in same answer of fields, want display error when type in duplicate answer.
here's 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 attempt @ custom attribute:
public class uniqueanswersonly: validationattribute, iclientvalidatable { protected override validationresult isvalid(object value, validationcontext validationcontext) { //get list of properties marked [uniqueanswersonly] var props = validationcontext.objectinstance.gettype().getproperties().where( prop => attribute.isdefined(prop, typeof(uniqueanswersonly))); var values = new hashset<string>(); //read values of 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 + " required!", validationtype = "duplicateanswers" }; yield return rule; } }
the problem i'm having the validation sucessful though enter in duplicate answers. can still continue next dialog (i expecting validation fail if duplicates entered). think it's because custom attribute isn't being fired or hit because added breakpoints nothing hit.
in controller, have if(modelstate.isvalid) { //continue next dialog}
, model state return valid.
you create custom validation attribute this:
public class uniqueanswersonly : validationattribute { protected override validationresult isvalid(object value, validationcontext validationcontext) { //get list of properties marked [uniqueanswersonly] var props = validationcontext.objectinstance.gettype().getproperties().where( prop => attribute.isdefined(prop, typeof(uniqueanswersonly))); var values = new hashset<string>(); //read values of 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 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 default mvc project , added current code. validation works fine.
i added 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 askquestions view looks this:
@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 list", "index") </div> @section scripts { @scripts.render("~/bundles/jqueryval") }
if run app modelstate.isvalid() false if enter 2 identical answers. , setting breakpoint in validation routine shows it's being run.
Comments
Post a Comment