zhaolei
2020-11-20 921de2254ff5712a44ed8575ee8efe34252f6603
commit | author | age
921de2 1 using Microsoft.AspNetCore.Components.Forms;
Z 2 using System;
3 using System.Collections.Concurrent;
4 using System.Collections.Generic;
5 using System.ComponentModel.DataAnnotations;
6 using System.Linq;
7 using System.Reflection;
8
9 namespace Bootstrap.Admin.Pages.Components
10 {
11     /// <summary>
12     /// 
13     /// </summary>
14     public static class BootstrapAdminEditContextDataAnnotationsExtensions
15     {
16         private static ConcurrentDictionary<(Type ModelType, string FieldName), PropertyInfo> _propertyInfoCache = new ConcurrentDictionary<(Type, string), PropertyInfo>();
17
18         /// <summary>
19         /// 
20         /// </summary>
21         /// <param name="editContext">The <see cref="EditContext"/>.</param>
22         /// <param name="editForm"></param>
23         public static EditContext AddBootstrapAdminDataAnnotationsValidation(this EditContext editContext, LgbEditFormBase editForm)
24         {
25             if (editContext == null)
26             {
27                 throw new ArgumentNullException(nameof(editContext));
28             }
29
30             var messages = new ValidationMessageStore(editContext);
31
32             editContext.OnValidationRequested +=
33                 (sender, eventArgs) => ValidateModel(sender as EditContext, messages, editForm);
34
35             editContext.OnFieldChanged +=
36                 (sender, eventArgs) => ValidateField(editContext, messages, eventArgs.FieldIdentifier, editForm);
37
38             return editContext;
39         }
40
41         private static void ValidateModel(EditContext? editContext, ValidationMessageStore messages, LgbEditFormBase editForm)
42         {
43             if (editContext != null)
44             {
45                 var validationContext = new ValidationContext(editContext.Model);
46                 var validationResults = new List<ValidationResult>();
47                 Validator.TryValidateObject(editContext.Model, validationContext, validationResults, true);
48                 editForm.ValidateObject(editContext.Model, validationContext, validationResults);
49
50                 messages.Clear();
51
52                 foreach (var validationResult in validationResults)
53                 {
54                     if (!validationResult.MemberNames.Any())
55                     {
56                         messages.Add(new FieldIdentifier(editContext.Model, fieldName: string.Empty), validationResult.ErrorMessage);
57                         continue;
58                     }
59
60                     foreach (var memberName in validationResult.MemberNames)
61                     {
62                         messages.Add(editContext.Field(memberName), validationResult.ErrorMessage);
63                     }
64                 }
65                 editContext.NotifyValidationStateChanged();
66             }
67         }
68
69         private static void ValidateField(EditContext editContext, ValidationMessageStore messages, in FieldIdentifier fieldIdentifier, LgbEditFormBase editForm)
70         {
71             if (TryGetValidatableProperty(fieldIdentifier, out var propertyInfo))
72             {
73                 var propertyValue = propertyInfo.GetValue(fieldIdentifier.Model);
74                 var validationContext = new ValidationContext(fieldIdentifier.Model)
75                 {
76                     MemberName = propertyInfo.Name
77                 };
78                 var results = new List<ValidationResult>();
79
80                 Validator.TryValidateProperty(propertyValue, validationContext, results);
81                 editForm.ValidateProperty(propertyValue, validationContext, results);
82
83                 messages.Clear(fieldIdentifier);
84                 messages.Add(fieldIdentifier, results.Select(result => result.ErrorMessage));
85
86                 editContext.NotifyValidationStateChanged();
87             }
88         }
89
90 #nullable disable
91         internal static bool TryGetValidatableProperty(in FieldIdentifier fieldIdentifier, out PropertyInfo propertyInfo)
92         {
93             var cacheKey = (ModelType: fieldIdentifier.Model.GetType(), fieldIdentifier.FieldName);
94             if (!_propertyInfoCache.TryGetValue(cacheKey, out propertyInfo))
95             {
96                 // Validator.TryValidateProperty 只能对 Public 属性生效
97                 propertyInfo = cacheKey.ModelType.GetProperty(cacheKey.FieldName);
98
99                 _propertyInfoCache[cacheKey] = propertyInfo;
100             }
101
102             return propertyInfo != null;
103         }
104 #nullable restore
105     }
106 }