Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
259 views
in Technique[技术] by (71.8m points)

c# - Validation Framework in .NET that can do edits between fields

From my experience many validation frameworks in .NET allow you to validate a single field at a time for doing things like ensuring a field is a postal code or email address for instance. I usually call these within-field edits.

In my project we often have to do between-field-edits though. For instance, if you have a class like this:

public class Range
{
    public int Min { get; set; }
    public int Max { get; set; }
}

you might want to ensure that Max is greater than Min. You might also want to do some validation against an external object. For instance given you have a class like this:

public class Person
{
    public string PostalCode { get; set; }
}

and for whatever reason you want to ensure that Postal Code exists in a database or a file provided to you. I have more complex examples like where a user provides a data dictionary and you want to validate your object against that data dictionary.

My question is: can we use any of the existing validation frameworks (TNValidate, NHibernate Validator) for .NET or do we need to use a rules engine or what?? How do you people in the real world deal with this situation? :-)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There's only one validation framework that I know well and that is Enterprise Library Validation Application Block, or VAB for short. I will answer your questions from the context of the VAB.

First question: Can you do state (between-field) validation in VAB?

Yes you can. There are multiple ways to do this. You can choose for the self validation mechanism, as follows:

[HasSelfValidation]
public class Range
{
    public int Min { get; set; }
    public int Max { get; set; }

    [SelfValidation]
    public void ValidateRange(ValidationResults results)
    {
        if (this.Max < this.Min)
        {
            results.AddResult(
                new ValidationResult("Max less than min", this, "", "", null));
        }
    }
}

I must say I personally don't like this type of validations, especially when validating my domain entities, because I like to keep my validations separate from the validation logic (and keep my domain logic free from references to any validation framework). However, they need considerably less code than the alternative, which is writing a custom validator class. Here's an example:

[ConfigurationElementType(typeof(CustomValidatorData))]
public sealed class RangeValidator : Validator
{
    public RangeValidator(NameValueCollection attributes)
        : base(string.Empty, string.Empty) { }

    protected override string DefaultMessageTemplate
    {
        get { throw new NotImplementedException(); }
    }

    protected override void DoValidate(object objectToValidate,
        object currentTarget, string key, ValidationResults results)
    {
        Range range = (Range)currentTarget;

        if (range.Max < range.Min)
        {
            this.LogValidationResult(results,
                "Max less than min", currentTarget, key);
        }
    }
}

After writing this class you can hook this class up in your validation configuration file like this:

<validation>
  <type name="Range" defaultRuleset="Default" assemblyName="[Range Assembly]">
    <ruleset name="Default">
      <validator type="[Namespace].RangeValidator, [Validator Assembly]"
        name="Range Validator" />
    </ruleset>
  </type>
</validation> 

Second question: How to do complex validations with possible interaction a database (with VAB).

The examples I give for the first question are also usable for this. You can use the same techniques: self validation and custom validator. Your scenario where you want to check a value in a database is actually a simple one, because the validity of your object is not based on its context. You can simply check the state of the object against the database. It gets more complicated when the context in which an object lives gets important (but it is possible with VAB). Imagine for instance that you want to write a validation that ensures that every customer, at a given moment in time, has no more than two unshipped orders. This not only means that you have to check the database, but perhaps new orders that are added or orders are deleted within that same context. This problem is not VAB specific, you will have the same problems with every framework you choose. I've written an article that describes the complexities we're facing with in these situations (read and shiver).

Third question: How do you people in the real world deal with this situation?

I do these types of validation with the VAB in production code. It works great, but VAB is not very easy to learn. Still, I love what we can do with VAB, and it will only get better when v5.0 comes out. When you want to learn it, start with reading the ValidationHOL.pdf document that you can found in the Hands-On Labs download.

I hope this helps.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...