I debugged that all and noticed, that validator constructor is called (and not one time, that strangely). That is my IoC factory works properly.
Custom validation with service calls (rules with rulesets) works normally (I debugged – calls made). But standard validation rules (NotEmpty, Length, Matches and Must for Categories property) don’t work – no validation errors in ModelState object.
That all works early, I don’t change any of code posted here. No global model binders were changed/added. I have no ideas.
Code for model with not non-working validation:
My post action:
[HttpPost]
public ActionResult CreateTest([CustomizeValidator(RuleSet = "New")] Test model)
{
if (ModelState.IsValid)
{
var testId = testService.CreateTest(model);
return RedirectToAction("Test", new { testId });
}
PrepareTestEdit(true);
return View("EditTest");
}
My model:
[Validator(typeof(TestValidator))]
public class Test
{
public Test()
{
Categories = new List<string>();
}
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string UrlName { get; set; }
public List<string> Categories { get; set; }
}
Validator:
public class TestValidator : AbstractValidator<Test>
{
public TestValidator(ITestService testService)
{
RuleSet("Edit", () =>
{
RuleFor(x => x.Title).
Must((model, title) => testService.ValidateTitle(title, model.Id)).WithMessage("1");
RuleFor(x => x.UrlName).
Must((model, urlName) => testService.ValidateUrlName(urlName, model.Id)).WithMessage("2");
});
RuleSet("New", () =>
{
RuleFor(x => x.Title).
Must(title => testService.ValidateTitle(title)).WithMessage("3");
RuleFor(x => x.UrlName).
Must(urlName => testService.ValidateUrlName(urlName)).WithMessage("4");
});
RuleFor(x => x.Title).
NotEmpty().WithMessage("5").
Length(1, 100).WithMessage("6");
RuleFor(x => x.UrlName).
NotEmpty().WithMessage("7").
Length(1, 100).WithMessage("8").
Matches("^[-_a-zA-Z0-9]*$").WithMessage("9");
RuleFor(x => x.Description).
NotEmpty().WithMessage("10");
RuleFor(x => x.Categories).
Must(categories => categories != null && categories.Any()).WithMessage("11");
}
}
Fluent validation documentation
I placed all common rules to separate private method and call it for both rulesets in anonymous function body.