From ec74a3c491d361bbaf9354b7f17be750b7b8823c Mon Sep 17 00:00:00 2001 From: 杨宇千 Date: Sat, 17 Aug 2019 19:25:08 +0800 Subject: Add validation. --- Timeline/Models/Validation/Validator.cs | 107 ++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 Timeline/Models/Validation/Validator.cs (limited to 'Timeline/Models/Validation/Validator.cs') diff --git a/Timeline/Models/Validation/Validator.cs b/Timeline/Models/Validation/Validator.cs new file mode 100644 index 00000000..a1acbed9 --- /dev/null +++ b/Timeline/Models/Validation/Validator.cs @@ -0,0 +1,107 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Timeline.Models.Validation +{ + /// + /// A validator to validate value. + /// See . + /// + public interface IValidator + { + /// + /// Validate given value. + /// + /// The value to validate. + /// The validation message. + /// True if validation passed. Otherwise false. + bool Validate(object value, out string message); + } + + public static class ValidationConstants + { + public const string SuccessMessage = "Validation succeeded."; + } + + /// + /// Convenient base class for validator. + /// + /// The type of accepted value. + /// + /// Subclass should override to do the real validation. + /// This class will check the nullity and type of value. If value is null or not of type + /// it will return false and not call . + /// + /// If you want some other behaviours, write the validator from scratch. + /// + public abstract class Validator : IValidator + { + public bool Validate(object value, out string message) + { + if (value == null) + { + message = "Value is null."; + return false; + } + + if (value is T v) + { + + return DoValidate(v, out message); + } + else + { + message = $"Value is not of type {typeof(T).Name}"; + return false; + } + } + + protected abstract bool DoValidate(T value, out string message); + } + + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, + AllowMultiple = false)] + public class ValidateWithAttribute : ValidationAttribute + { + private readonly IValidator _validator; + + /// + /// Create with a given validator. + /// + /// The validator used to validate. + public ValidateWithAttribute(IValidator validator) + { + _validator = validator ?? throw new ArgumentNullException(nameof(validator)); + } + + /// + /// Create the validator with default constructor. + /// + /// The type of the validator. + public ValidateWithAttribute(Type validatorType) + { + if (validatorType == null) + throw new ArgumentNullException(nameof(validatorType)); + + if (!typeof(IValidator).IsAssignableFrom(validatorType)) + throw new ArgumentException("Given type is not assignable to IValidator.", nameof(validatorType)); + + try + { + _validator = Activator.CreateInstance(validatorType) as IValidator; + } + catch (Exception e) + { + throw new ArgumentException("Failed to create a validator instance from default constructor. See inner exception.", e); + } + } + + protected override ValidationResult IsValid(object value, ValidationContext validationContext) + { + if (_validator.Validate(value, out var message)) + return ValidationResult.Success; + else + return new ValidationResult(string.Format("Field {0} is bad. {1}", validationContext.DisplayName, message)); + } + } +} -- cgit v1.2.3