Skip to content

Commit 005956f

Browse files
committed
Use the unified validation instractructure for EditForm validation
1 parent aebd07a commit 005956f

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

src/Components/Forms/src/EditContextDataAnnotationsExtensions.cs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
using System.Reflection;
88
using System.Reflection.Metadata;
99
using System.Runtime.InteropServices;
10+
using Microsoft.AspNetCore.Http.Validation;
11+
using Microsoft.Extensions.DependencyInjection;
12+
using Microsoft.Extensions.Options;
1013

1114
[assembly: MetadataUpdateHandler(typeof(Microsoft.AspNetCore.Components.Forms.EditContextDataAnnotationsExtensions))]
1215

@@ -112,6 +115,13 @@ private void OnFieldChanged(object? sender, FieldChangedEventArgs eventArgs)
112115
private void OnValidationRequested(object? sender, ValidationRequestedEventArgs e)
113116
{
114117
var validationContext = new ValidationContext(_editContext.Model, _serviceProvider, items: null);
118+
119+
if (TryValidateTypeInfo(validationContext))
120+
{
121+
_editContext.NotifyValidationStateChanged();
122+
return;
123+
}
124+
115125
var validationResults = new List<ValidationResult>();
116126
Validator.TryValidateObject(_editContext.Model, validationContext, validationResults, true);
117127

@@ -140,6 +150,52 @@ private void OnValidationRequested(object? sender, ValidationRequestedEventArgs
140150
_editContext.NotifyValidationStateChanged();
141151
}
142152

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+
143199
public void Dispose()
144200
{
145201
_messages.Clear();
@@ -174,5 +230,20 @@ internal void ClearCache()
174230
{
175231
_propertyInfoCache.Clear();
176232
}
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+
}
177248
}
178249
}

src/Components/Forms/src/Microsoft.AspNetCore.Components.Forms.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
<ItemGroup>
1313
<Reference Include="Microsoft.AspNetCore.Components" />
14+
<Reference Include="Microsoft.AspNetCore.Http.Abstractions" />
1415
</ItemGroup>
1516

1617
<ItemGroup>

0 commit comments

Comments
 (0)