I have a custom validation in the enterprise validation block. The DoValidate
method is as shown below.
protected override void DoValidate(Double objectToValidate,
object currentTarget, string key, ValidationResults validationResults)
{
if (!IsSalMoreThanMinWage(objectToValidate))
{
//Here I need to mark this message as a "Warning"
LogValidationResult(validationResults,
"Salary is too low for this state", currentTarget, key);
}
}
I'd need to mark this validation failure as a "warning" message. In the front end, when I iterate through the ValidationResults
collection and grab a ValidationResult
object, I would need to identify and group different types of messages and re开发者_开发知识库nder them differently.
My question is - how do I mark a failure as a warning?
You can use the Tag
property of the ValidationResult
. "The meaning for a tag is determined by the client code consuming the ValidationResults."
If you are using configuration, then you can specify the tag in your configuration file:
<validator lowerBound="0" lowerBoundType="Inclusive"
upperBound="255" upperBoundType="Inclusive" negated="false" messageTemplateResourceName="" messageTemplateResourceType=""
messageTemplate="Oops a warning occurred"
tag="Warning" type="Microsoft.Practices.EnterpriseLibrary.Validation.Validators.StringLengthValidator, Microsoft.Practices.EnterpriseLibrary.Validation, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="My Validator" />
Or set the Tag with a property:
[StringLengthValidator(5, 50, Ruleset = "RuleSetA", Tag="Warning")]
If you want to do it programmatically, then you will have to create a new validation result since the Tag property is readonly:
ValidationResults newResults = new ValidationResults();
foreach (ValidationResult vr in validationResults)
{
newResults.AddResult( new ValidationResult(
vr.Message, vr.Target, vr.Key, "Warning", vr.Validator, vr.NestedValidationResults ) );
}
Then in the front end you can check the Tag property of the ValidationResult to see if it's a warning:
foreach (ValidationResult vr in validationResults)
{
if (string.Compare(vr.Tag, "Warning") == 0)
{
DisplayWarning(vr.Message);
}
else
{
DisplayError(vr.Message);
}
}
Obviously, you can abstract this much better, aggregate the errors and warnings etc.
UPDATE
We don't have identical requirements to yours but we do something similar. Unfortunately, the only way I know to execute the type of conditional validation you are talking about is to use RuleSets.
What we do is use a naming convention for the RuleSets and construct the RuleSet Names at runtime. If the RuleSet exists then we run the validator. You could do something similar for your warnings. So you could have two RuleSets:
- RuleSet_Salary_Update
- RuleSet_Salary_Update_Warning
And then retrieve a List of Validators based on whether you want to run the warning validation:
public static List<Validator<T>> CreateValidators<T>(bool shoulIncludeWarning, RuleSetType rulesetType)
{
if (shouldIncludeWarning)
{
// Get warning validator if any
}
// Get Default validator (if any)
}
RuleSetType is an enum with different types of rules (e.g. Select, Insert, Update, Delete, PrimaryKey, etc.).
Short answer:
Create an non-default ruleset and name it 'Warning'.
Long answer:
Validation Application block supports the notion of 'rulesets'. You can make a ruleset named 'Warning'. How to use this depends on your architecture and interface, but here is an idea.
It a bit depends whether you always want to show both errors and warnings, or only show errors when there are errors, and otherwise show the warnings or save. When there are warnings the user need to be able to say "hell yes I'm sure, save it!" and then you need to save the changes by suppressing the errors.
When you follow this approach you can throw an exception (say ValidationException
) that holds the ValidationResult
objects. Add a property to the exception that says whether the results are warnings or errors (you can do this when you decide to don't show any warnings when there are errors).
In your presentation layer you do the following:
Button_Save(object sender, EventArgs e)
{
this.Save(ValidationMode.Default);
}
Button_HellYesSuppresWarningsAndSave(object sender, EventArgs e)
{
this.Save(ValidationMode.SuppressWarnings);
}
private Save(ValidationMode mode)
{
try
{
ServiceLayer.Save(mode);
}
catch (ValidationException ex)
{
if (ex.ResultType == ValidationResultType.Warnings)
{
ShowWarningsAndAskIfSure(ex.Errors);
}
else
{
ShowErrorsAndTellUserNeedsToFix(ex.Errors);
}
}
}
In the business layer you need to to something like this:
public void Save(ValidationMode mode)
{
Validate(ValidationResultType.Errors);
if (!mode == ValidationMode.SuppressWarnings)
{
Validate(ValidationResultType.Warnings);
}
}
private void Validate(ValidationResultType type)
{
var objectToValidate;
var ruleset = type == ValidationResultType.Errors ? "default" : "warnings";
var validator = ValidationFactory
.CreateValidator(objectToValidate.GetType(), ruleset);
var results = validator.Validate();
if (!results.IsValid)
{
throw new ValidationException(results, type);
}
}
I hope this makes sense.
精彩评论