I'm create C# windows application and using FluentValidation for validating a View Model. In every form I always create validation method like this:
private bool ValidateCustomer(CustomerViewModel customerVM)
{
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customerVM);
if (!results.IsValid)
{
StringBuilder errorMessage = new StringBuilder("Data Validation Checking Error:\n");
foreach (var failure in results.Errors)
{
errorMessage.AppendLine("- " + failure.ErrorMessage);
}
MessageBox.Show(errorMessage.ToString(), "Exclamation", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return false;
}
return true;
}
public class CustomerValidator : AbstractValidator<CustomerViewModel>
{
public CustomerValidator()
{
RuleFor(c => c.Code).NotEmpty();
RuleFor(c => c.Name).NotEmpty();
}
}
I want to create Generic ValidationHelper class so that I don't write the same validation code (just different validator and viewmodel class) in every form, for example:
ValidationHelper<MyValidator, MyViewModel>.Validate()
. I'm just replace MyValidator and MyViewModel class for the other form. When make this Generic class I'm having problem when instantiate a validator class.
public static class ValidatorHelper<T, V>
where T : class, new()
where V : class, new()
{
public static bool Validate(T t, V n)
{
T validator = new T();
ValidationResult results = validator.Validate(n); // <--- error on this line
if (!results.IsValid)
{
StringBuilder errorMessage = new StringBuilder("Data Validation Checking Error:\n");
foreach (var failure in results.Errors)
{
errorMessage.AppendLine("- " + failure.ErrorMessage);
}
MessageBox.Show(errorMessage.ToString(), "Exclamation", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return false;
}
return true;
}
}
How to solve this problem?
UPDATE:
As @JonSkeet and @dbc suggestion, I modified the ValidatorHelper to:
public static class ValidatorHelper<T, V>
where T : AbstractValidator<V>, new()
where V : class, new()
{
public static bool Validate(V v)
{
T validator = new T();
ValidationResult results = validator.Validate(v);
if (!results.IsValid)
{
StringBuilder errorMessage = new StringBuilder("Data Validation Checking Error:\n");
foreach (var failure in results.Errors)
{
errorMessage.AppendLine("- " + failure.ErrorMessage);
//log.Message("Property " + failure.PropertyName + " failed validation. Error was: " + failure.ErrorMessage);
}
MessageBox.Show(errorMessage.ToString(), "Exclamation", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return false;
}
return true;
}
}
I'm not using T on public static bool Validate(V v)
because it will be instantiated in it. Then on the form, you've just write:
if (ValidatorHelper<CustomerValidator, CustomerViewModel>.Validate(customerVM))
Thanks to you both, I can solve the problem, I really appreciate it.
You're trying to assign a CustomerValidator
reference to a variable of type T
. What if T
is StringBuilder
or something like that?
Fundamentally, it seems odd for your ValidationHelper
to claim to be generic, but then be specific to CustomerValidator
.
Without knowing about the FluentValidation library, we can't really know what CustomerValidator
does - does it implement Validator<Customer>
for example? It strikes me that you might want to pass the validator into the Validate
method, or into the ValidatorHelper
constructor. (I strongly suspect that you want to get rid of both of the static modifiers - if the method is static, it can't be implementing an abstract method in the base class... and if the class is static, it can't even specific a base class.)
Fundamentally, you need to consider:
CustomerValidator
? Probably not a generic helper class.new()
constraint, potentially)Validate
methodYou may want something like this:
// No constraint on V - why would you need one?
public class ValidatorHelper<T, V> : AbstractValidator<V>
where T : AbstractValidator<V>
{
public bool Validate(T validator, V value)
{
ValidationResult results = validator.Validate(value);
if (!results.IsValid)
{
StringBuilder errorMessage = new StringBuilder("Data Validation Checking Error:\n");
foreach (var failure in results.Errors)
{
errorMessage.AppendLine("- " + failure.ErrorMessage);
}
MessageBox.Show(errorMessage.ToString(), "Exclamation", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return false;
}
return true;
}
}
See more on this question at Stackoverflow