using System; using System.Collections.Generic; using System.Text; using ServiceStack.Model; using ServiceStack.Text; namespace ServiceStack.Validation { /// /// The exception which is thrown when a validation error occurred. /// This validation is serialized in a extra clean and human-readable way by ServiceStack. /// public class ValidationError : ArgumentException, IResponseStatusConvertible { public string ErrorMessage { get; } public ValidationError(string errorCode) : this(errorCode, errorCode.SplitCamelCase()) { } public ValidationError(ValidationErrorResult validationResult) : base(validationResult.ErrorMessage) { this.ErrorCode = validationResult.ErrorCode; this.ErrorMessage = validationResult.ErrorMessage; this.Violations = validationResult.Errors; } public ValidationError(ValidationErrorField validationError) : this(validationError.ErrorCode, validationError.ErrorMessage) { this.Violations.Add(validationError); } public ValidationError(string errorCode, string errorMessage) : base(errorMessage) { this.ErrorCode = errorCode; this.ErrorMessage = errorMessage; this.Violations = new List(); } /// /// Returns the first error code /// /// The error code. public string ErrorCode { get; } public override string Message { get { //If there is only 1 validation error than we just show the error message if (this.Violations.Count == 0) return this.ErrorMessage; if (this.Violations.Count == 1) return this.ErrorMessage ?? this.Violations[0].ErrorMessage; var sb = StringBuilderCache.Allocate() .Append(this.ErrorMessage).AppendLine(); foreach (var error in this.Violations) { if (!string.IsNullOrEmpty(error.ErrorMessage)) { var fieldLabel = error.FieldName != null ? $" [{error.FieldName}]" : null; sb.Append($"\n - {error.ErrorMessage}{fieldLabel}"); } else { var fieldLabel = error.FieldName != null ? ": " + error.FieldName : null; sb.Append($"\n - {error.ErrorCode}{fieldLabel}"); } } return StringBuilderCache.ReturnAndFree(sb); } } public IList Violations { get; private set; } /// /// Used if we need to serialize this exception to XML /// /// public string ToXml() { var sb = StringBuilderCache.Allocate(); sb.Append(""); foreach (var error in this.Violations) { sb.Append("") .Append($"{error.ErrorCode}") .Append($"{error.FieldName}") .Append($"{error.ErrorMessage}") .Append(""); } sb.Append(""); return StringBuilderCache.ReturnAndFree(sb); } public static ValidationError CreateException(Enum errorCode) { return new ValidationError(errorCode.ToString()); } public static ValidationError CreateException(Enum errorCode, string errorMessage) { return new ValidationError(errorCode.ToString(), errorMessage); } public static ValidationError CreateException(Enum errorCode, string errorMessage, string fieldName) { return CreateException(errorCode.ToString(), errorMessage, fieldName); } public static ValidationError CreateException(string errorCode) { return new ValidationError(errorCode); } public static ValidationError CreateException(string errorCode, string errorMessage) { return new ValidationError(errorCode, errorMessage); } public static ValidationError CreateException(string errorCode, string errorMessage, string fieldName) { var error = new ValidationErrorField(errorCode, fieldName, errorMessage); return new ValidationError(new ValidationErrorResult(new List { error })); } public static ValidationError CreateException(ValidationErrorField error) { return new ValidationError(error); } public static void ThrowIfNotValid(ValidationErrorResult validationResult) { if (!validationResult.IsValid) { throw new ValidationError(validationResult); } } public ResponseStatus ToResponseStatus() { return ResponseStatusUtils.CreateResponseStatus(ErrorCode, Message, Violations); } } }