|
7 | 7 | using System.Reflection;
|
8 | 8 | using System.Reflection.Metadata;
|
9 | 9 | using System.Runtime.InteropServices;
|
| 10 | +using Microsoft.AspNetCore.Http.Validation; |
| 11 | +using Microsoft.Extensions.DependencyInjection; |
| 12 | +using Microsoft.Extensions.Options; |
10 | 13 |
|
11 | 14 | [assembly: MetadataUpdateHandler(typeof(Microsoft.AspNetCore.Components.Forms.EditContextDataAnnotationsExtensions))]
|
12 | 15 |
|
@@ -112,6 +115,13 @@ private void OnFieldChanged(object? sender, FieldChangedEventArgs eventArgs)
|
112 | 115 | private void OnValidationRequested(object? sender, ValidationRequestedEventArgs e)
|
113 | 116 | {
|
114 | 117 | var validationContext = new ValidationContext(_editContext.Model, _serviceProvider, items: null);
|
| 118 | + |
| 119 | + if (TryValidateTypeInfo(validationContext)) |
| 120 | + { |
| 121 | + _editContext.NotifyValidationStateChanged(); |
| 122 | + return; |
| 123 | + } |
| 124 | + |
115 | 125 | var validationResults = new List<ValidationResult>();
|
116 | 126 | Validator.TryValidateObject(_editContext.Model, validationContext, validationResults, true);
|
117 | 127 |
|
@@ -140,6 +150,52 @@ private void OnValidationRequested(object? sender, ValidationRequestedEventArgs
|
140 | 150 | _editContext.NotifyValidationStateChanged();
|
141 | 151 | }
|
142 | 152 |
|
| 153 | +#pragma warning disable ASP0029 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. |
| 154 | + private bool TryValidateTypeInfo(ValidationContext validationContext) |
| 155 | + { |
| 156 | + var options = _serviceProvider?.GetService<IOptions<ValidationOptions>>()?.Value; |
| 157 | + |
| 158 | + if (options == null || !options.TryGetValidatableTypeInfo(_editContext.Model.GetType(), out var typeInfo)) |
| 159 | + { |
| 160 | + return false; |
| 161 | + } |
| 162 | + |
| 163 | + var validateContext = new ValidateContext |
| 164 | + { |
| 165 | + ValidationOptions = options, |
| 166 | + ValidationContext = validationContext, |
| 167 | + }; |
| 168 | + |
| 169 | + var validationTask = typeInfo.ValidateAsync(_editContext.Model, validateContext, CancellationToken.None); |
| 170 | + |
| 171 | + if (!validationTask.IsCompleted) |
| 172 | + { |
| 173 | + throw new InvalidOperationException("Async validation is not supported"); |
| 174 | + } |
| 175 | + |
| 176 | + var validationErrors = validateContext.ValidationErrors; |
| 177 | + |
| 178 | + // Transfer results to the ValidationMessageStore |
| 179 | + _messages.Clear(); |
| 180 | + |
| 181 | + if (validationErrors is not null && validationErrors.Count > 0) |
| 182 | + { |
| 183 | + foreach (var (key, value) in validationErrors) |
| 184 | + { |
| 185 | + var keySegments = key.Split('.'); |
| 186 | + var container = keySegments.Length > 1 |
| 187 | + ? GetPropertyByPath(_editContext.Model, keySegments[..^1]) |
| 188 | + : _editContext.Model; |
| 189 | + var fieldName = keySegments[^1]; |
| 190 | + |
| 191 | + _messages.Add(new FieldIdentifier(container, fieldName), value); |
| 192 | + } |
| 193 | + } |
| 194 | + |
| 195 | + return true; |
| 196 | + } |
| 197 | +#pragma warning restore ASP0029 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. |
| 198 | + |
143 | 199 | public void Dispose()
|
144 | 200 | {
|
145 | 201 | _messages.Clear();
|
@@ -174,5 +230,20 @@ internal void ClearCache()
|
174 | 230 | {
|
175 | 231 | _propertyInfoCache.Clear();
|
176 | 232 | }
|
| 233 | + |
| 234 | + // TODO(OR): Replace this with more robust implementation. |
| 235 | + private static object GetPropertyByPath(object obj, string[] path) |
| 236 | + { |
| 237 | + var currentObject = obj; |
| 238 | + |
| 239 | + foreach (string propertyName in path) |
| 240 | + { |
| 241 | + Type currentType = currentObject!.GetType(); |
| 242 | + PropertyInfo propertyInfo = currentType.GetProperty(propertyName)!; |
| 243 | + currentObject = propertyInfo.GetValue(currentObject); |
| 244 | + } |
| 245 | + |
| 246 | + return currentObject!; |
| 247 | + } |
177 | 248 | }
|
178 | 249 | }
|
0 commit comments