LoginSignup
6
12

More than 5 years have passed since last update.

[ASP .NET MVC 5] 入れ子のModelのValidationを行う

Posted at

ASP .NET MVC 5で確認。

入れ子のModelのValidationは効かない。
Attachmentの中のNameAndExtensionとかのRequiredはValidationされない。

    public class Email
    {
        [Required]
        public string From { get; set; }

        [Required]
        public string Subject { get; set; }

        public string Body { get; set; }

        [Required]
        public EmailAttachment Attachment { get; set; }


        public Email()
        {
        }

        public class EmailAttachment
        {
            [Required]
            public string NameAndExtension { get; set; }

            [Required]
            public byte[] File { get; set; }
        }
    }

子のValidationを行うためのAttributeを作成する

    /// <summary>
    /// 子オブジェクトのValidationも行います
    /// </summary>
    public class NestedValidateAttribute : ValidationAttribute
    {
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (value == null) return ValidationResult.Success;
            var results = new List<ValidationResult>();
            var context = new ValidationContext(value, null, null);
            //Validationを実施
            Validator.TryValidateObject(value, context, results, true);

            if (results.Count != 0)
            {
                var validationResults = results.Select(x => new ValidationResult(x.ErrorMessage, x.MemberNames.Select(y => $"{validationContext.DisplayName}.{y}")));
                var compositeResults = new CompositeValidationResult(String.Format("Validation for {0} failed!", new { validationContext.DisplayName }));
                compositeResults.AddResults(validationResults);
                return compositeResults;

            }

            return ValidationResult.Success;
        }
    }
    /// <summary>
    /// 複数のValidation結果を格納できる<see cref="ValidationResult" />
    /// </summary>
    public class CompositeValidationResult : ValidationResult
    {
        /// <summary>
        /// 複数のValidation結果
        /// </summary>
        public IEnumerable<ValidationResult> Results { get;} = new List<ValidationResult>();

        public CompositeValidationResult(string errorMessage) : base(errorMessage) { }
        public CompositeValidationResult(string errorMessage, IEnumerable<string> memberNames) : base(errorMessage, memberNames) { }
        protected CompositeValidationResult(ValidationResult validationResult) : base(validationResult) { }
        /// <summary>
        /// エラーを登録
        /// </summary>
        /// <param name="validationResult"></param>
        public void AddResult(ValidationResult validationResult)
        {
            (Results as IList<ValidationResult>).Add(validationResult);
        }
        /// <summary>
        /// エラーを登録
        /// </summary>
        /// <param name="validationResults"></param>
        public void AddResults(IEnumerable<ValidationResult> validationResults)
        {
            (Results as List<ValidationResult>).AddRange(validationResults);
        }
    }

使うときはこんな感じでAttachmentにNestedValidate属性をつければよい。

    public class Email
    {
        [Required]
        public string From { get; set; }

        [Required]
        public string Subject { get; set; }

        public string Body { get; set; }

        [Required]
        [NestedValidate]
        public EmailAttachment Attachment { get; set; }


        public Email()
        {
        }

        public class EmailAttachment
        {
            [Required]
            public string NameAndExtension { get; set; }

            [Required]
            public byte[] File { get; set; }
        }
    }

Controller内で確認.
ModelState内にValidation結果が格納されている。

        public ActionResult Create(Email viewModel)
        {
            var errors = ModelState
                .Where(x => x.Value.Errors.Count > 0)
                .Select(y =>
                new
                {
                    MemberName = y.Key,
                    ErrorMessages = y.Value.Errors.Select(e => e.ErrorMessage).ToArray(),
                    Exception = y.Value.Errors.Select(e => e.Exception).FirstOrDefault()?.ToString()
                });

/*以下略*/
        }

参考:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/4cbf4482-f4f5-489d-bbf1-65810f307d16/data-annontation-validation-with-nested-object?forum=csharpgeneral

6
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
12