From 05ccb4d8f1bbe3fb64e117136b4a89bcfb0b0b33 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 27 Oct 2020 19:21:35 +0800 Subject: Split front and back end. --- BackEnd/Timeline/Models/Validation/Validator.cs | 127 ++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 BackEnd/Timeline/Models/Validation/Validator.cs (limited to 'BackEnd/Timeline/Models/Validation/Validator.cs') diff --git a/BackEnd/Timeline/Models/Validation/Validator.cs b/BackEnd/Timeline/Models/Validation/Validator.cs new file mode 100644 index 00000000..aef7891c --- /dev/null +++ b/BackEnd/Timeline/Models/Validation/Validator.cs @@ -0,0 +1,127 @@ +using System; +using System.ComponentModel.DataAnnotations; +using static Timeline.Resources.Models.Validation.Validator; + +namespace Timeline.Models.Validation +{ + /// + /// A validator to validate value. + /// + public interface IValidator + { + /// + /// Validate given value. + /// + /// The value to validate. + /// Validation success or not and message. + (bool, string) Validate(object? value); + } + + public static class ValidatorExtensions + { + public static bool Validate(this IValidator validator, object? value, out string message) + { + if (validator == null) + throw new ArgumentNullException(nameof(validator)); + + var (r, m) = validator.Validate(value); + message = m; + return r; + } + } + + /// + /// 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, it will pass or fail depending on . + /// If value is not null and not of type + /// it will fail and not call . + /// + /// is true by default. + /// + /// If you want some other behaviours, write the validator from scratch. + /// + public abstract class Validator : IValidator + { + protected bool PermitNull { get; set; } = true; + + public (bool, string) Validate(object? value) + { + if (value == null) + { + if (PermitNull) + return (true, GetSuccessMessage()); + else + return (false, ValidatorMessageNull); + } + + if (value is T v) + { + return DoValidate(v); + } + else + { + return (false, ValidatorMessageBadType); + } + } + + protected static string GetSuccessMessage() => ValidatorMessageSuccess; + + protected abstract (bool, string) DoValidate(T value); + } + + [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(ValidateWithAttributeExceptionNotValidator, nameof(validatorType)); + + try + { + _validator = (Activator.CreateInstance(validatorType) as IValidator)!; + } + catch (Exception e) + { + throw new ArgumentException(ValidateWithAttributeExceptionCreateFail, e); + } + } + + protected override ValidationResult IsValid(object value, ValidationContext validationContext) + { + var (result, message) = _validator.Validate(value); + if (result) + { + return ValidationResult.Success; + } + else + { + return new ValidationResult(message); + } + } + } +} -- cgit v1.2.3