Suppose the following situation:
```
// [Validator(typeof(AddressForSupplierValidator))] <-- Cannot put both
// [Validator(typeof(AddressForCompanyValidator))] <--
// But even if I skip both of them it works great for SERVER SIDE
public class Address
{
public string AddressName { get; set; }
public string StreetName { get; set; }
}
[Validator(typeof(SupplierValidator))]
public class Supplier
{
public string Name { get; set; }
public Address Address { get; set; }
}
public class SupplierValidator: AbstractValidator<Supplier>
{
public SupplierValidator() {
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.Address).SetValidator(new AddressForSupplierValidator());
// AddressForSupplierValidator - Requires AddressName to be .NotEmpty()
}
}
[Validator(typeof(CompanyValidator))]
public class Company
{
public string Name { get; set; }
public Address Address { get; set; }
}
public class CompanyValidator: AbstractValidator<Company>
{
public CompanyValidator() {
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.Address).SetValidator(new AddressForCompanyValidator());
// AddressForCompanyValidator - Requires StreetName to be .NotEmpty()
}
}
```
As illustrated `Address` entity is being used by `Company` and by `Supplier`.
Now I need to validate `Address` depending on its context.
The above solution works for **SERVER SIDE** only. But for **CLIENT SIDE**:
> It doesn't generate `data-val-` attributes on HTML elements. This is
> because it lacks any `[Validator(..)]` on top `Address` class
> definition. Adding `[Validator(..)]` solves the `data-val-` generation
> but breaks the ideea of reusing `Address` entity and validate it
> depending on context
##Questions:
1. Why the absence of `[Validator()]` ontop of `Address` breaks CLIENT SIDE validaton, even with `.SetValidator()`?
2. Why do we need `RuleFor(x => x.Address).SetValidator(..);` if anyway the validator must be specified on top of the class ?
##Some thoughts:
1. My belief is that specifying `.SetValidator(..)` for a nested property should be enough. The requirement with adding `[Validator()]` breaks the ideea of reusing same ViewModel with many validation rules depending on context.
2. The author already did great job integrating the client validation. And they work if leaving the ideea of reusing the viewmodel.
##Temporary solution:
public class AddressBase
{
public string AddressName { get; set;}
public string StreetName { get; set;}
}
[Validator(typeof(AddressForSupplierValidator))]
public class SupplierAddress : AddressBase
{}
[Validator(typeof(AddressForCompanyValidator))]
public class CompanyAddress : AddressBase
{}
It works, but again whats the reason for `.SetValidator(new AddressForSupplierValidator());` then !? Kind of redundant.
###References:
Repost on SO : http://stackoverflow.com/questions/29412824/fluentvalidation-contextual-validators
Related SO question which demonstrates this issue is place at:
http://stackoverflow.com/questions/17238544/unobtrusive-client-validation-data-attributes-are-not-rendered-for-nested-proper
Comments: Apologies for not replying sooner - CodePlex has been in read-only mode for the last week so I've been unable to post comments. Because codeplex seems like it's now on its last legs, I've moved the project to github - if you'd like to continue the discussion please post again over there: http://github.com/JeremySkinner/FluentValidation > Why do we need RuleFor(x => x.Address).SetValidator(..); if anyway the validator must be specified on top of the class ? The [Validator] attribute and SetValidator are different - they don't do the same job. SetValidator is part of FluentValidation's core API, and is the "normal" way of validating a complex child property. The [Validator] attribute is different - this is a way of telling ASP.NET MVC's built-in validation API which validator should be connected to which class - primarily for the purposes of model-binding. Usually, you would only put the [Validator] attribute on the top level class (supplier/company) - you would *not* put it on Address. This way, you're telling MVC's model-binding infrastructure that it should instantiate the CompanyValidator, and then you'd let FluentValidation run through as normal, using SetValidator for the Address. Client-side validation breaks this - only a small subset of rules are available on the client: * NotNull/NotEmpty * Matches * Range * CreditCard * Email * EqualTo * Length More complicated rules such as SetValidator, Must and the When/Unless conditionals are not supported on client-side. You can work around SetValidator not working on the client as you found by decorating the child validator with a [Validator] attribute, but this is only a workaround - SetValidator is not really supported on the client, only the small collection of rules above.
```
// [Validator(typeof(AddressForSupplierValidator))] <-- Cannot put both
// [Validator(typeof(AddressForCompanyValidator))] <--
// But even if I skip both of them it works great for SERVER SIDE
public class Address
{
public string AddressName { get; set; }
public string StreetName { get; set; }
}
[Validator(typeof(SupplierValidator))]
public class Supplier
{
public string Name { get; set; }
public Address Address { get; set; }
}
public class SupplierValidator: AbstractValidator<Supplier>
{
public SupplierValidator() {
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.Address).SetValidator(new AddressForSupplierValidator());
// AddressForSupplierValidator - Requires AddressName to be .NotEmpty()
}
}
[Validator(typeof(CompanyValidator))]
public class Company
{
public string Name { get; set; }
public Address Address { get; set; }
}
public class CompanyValidator: AbstractValidator<Company>
{
public CompanyValidator() {
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.Address).SetValidator(new AddressForCompanyValidator());
// AddressForCompanyValidator - Requires StreetName to be .NotEmpty()
}
}
```
As illustrated `Address` entity is being used by `Company` and by `Supplier`.
Now I need to validate `Address` depending on its context.
The above solution works for **SERVER SIDE** only. But for **CLIENT SIDE**:
> It doesn't generate `data-val-` attributes on HTML elements. This is
> because it lacks any `[Validator(..)]` on top `Address` class
> definition. Adding `[Validator(..)]` solves the `data-val-` generation
> but breaks the ideea of reusing `Address` entity and validate it
> depending on context
##Questions:
1. Why the absence of `[Validator()]` ontop of `Address` breaks CLIENT SIDE validaton, even with `.SetValidator()`?
2. Why do we need `RuleFor(x => x.Address).SetValidator(..);` if anyway the validator must be specified on top of the class ?
##Some thoughts:
1. My belief is that specifying `.SetValidator(..)` for a nested property should be enough. The requirement with adding `[Validator()]` breaks the ideea of reusing same ViewModel with many validation rules depending on context.
2. The author already did great job integrating the client validation. And they work if leaving the ideea of reusing the viewmodel.
##Temporary solution:
public class AddressBase
{
public string AddressName { get; set;}
public string StreetName { get; set;}
}
[Validator(typeof(AddressForSupplierValidator))]
public class SupplierAddress : AddressBase
{}
[Validator(typeof(AddressForCompanyValidator))]
public class CompanyAddress : AddressBase
{}
It works, but again whats the reason for `.SetValidator(new AddressForSupplierValidator());` then !? Kind of redundant.
###References:
Repost on SO : http://stackoverflow.com/questions/29412824/fluentvalidation-contextual-validators
Related SO question which demonstrates this issue is place at:
http://stackoverflow.com/questions/17238544/unobtrusive-client-validation-data-attributes-are-not-rendered-for-nested-proper
Comments: Apologies for not replying sooner - CodePlex has been in read-only mode for the last week so I've been unable to post comments. Because codeplex seems like it's now on its last legs, I've moved the project to github - if you'd like to continue the discussion please post again over there: http://github.com/JeremySkinner/FluentValidation > Why do we need RuleFor(x => x.Address).SetValidator(..); if anyway the validator must be specified on top of the class ? The [Validator] attribute and SetValidator are different - they don't do the same job. SetValidator is part of FluentValidation's core API, and is the "normal" way of validating a complex child property. The [Validator] attribute is different - this is a way of telling ASP.NET MVC's built-in validation API which validator should be connected to which class - primarily for the purposes of model-binding. Usually, you would only put the [Validator] attribute on the top level class (supplier/company) - you would *not* put it on Address. This way, you're telling MVC's model-binding infrastructure that it should instantiate the CompanyValidator, and then you'd let FluentValidation run through as normal, using SetValidator for the Address. Client-side validation breaks this - only a small subset of rules are available on the client: * NotNull/NotEmpty * Matches * Range * CreditCard * Email * EqualTo * Length More complicated rules such as SetValidator, Must and the When/Unless conditionals are not supported on client-side. You can work around SetValidator not working on the client as you found by decorating the child validator with a [Validator] attribute, but this is only a workaround - SetValidator is not really supported on the client, only the small collection of rules above.