-
-
Notifications
You must be signed in to change notification settings - Fork 362
fix(BootstrapBlazorDataAnnotationsValidator): add IDispose interface #6543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,7 @@ namespace BootstrapBlazor.Components; | |
| /// <summary> | ||
| /// BootstrapBlazorDataAnnotationsValidator 验证组件 | ||
| /// </summary> | ||
| public class BootstrapBlazorDataAnnotationsValidator : ComponentBase | ||
| public class BootstrapBlazorDataAnnotationsValidator : ComponentBase, IDisposable | ||
| { | ||
| /// <summary> | ||
| /// 获得/设置 当前编辑数据上下文 | ||
|
|
@@ -23,30 +23,110 @@ public class BootstrapBlazorDataAnnotationsValidator : ComponentBase | |
| /// 获得/设置 当前编辑窗体上下文 | ||
| /// </summary> | ||
| [CascadingParameter] | ||
| [NotNull] | ||
| private ValidateForm? ValidateForm { get; set; } | ||
|
|
||
| [Inject] | ||
| [NotNull] | ||
| private IServiceProvider? Provider { get; set; } | ||
|
|
||
| [NotNull] | ||
| private ValidationMessageStore? _message = null; | ||
|
|
||
| /// <summary> | ||
| /// 初始化方法 | ||
| /// </summary> | ||
| protected override void OnInitialized() | ||
| { | ||
| if (ValidateForm == null) | ||
| { | ||
| throw new InvalidOperationException($"{nameof(Components.BootstrapBlazorDataAnnotationsValidator)} requires a cascading " + | ||
| $"parameter of type {nameof(Components.ValidateForm)}. For example, you can use {nameof(Components.BootstrapBlazorDataAnnotationsValidator)} " + | ||
| $"inside an {nameof(Components.ValidateForm)}."); | ||
| throw new InvalidOperationException($"{nameof(BootstrapBlazorDataAnnotationsValidator)} requires a cascading parameter of type {nameof(Components.ValidateForm)}. For example, you can use {nameof(BootstrapBlazorDataAnnotationsValidator)} inside an {nameof(Components.ValidateForm)}."); | ||
| } | ||
|
|
||
| CurrentEditContext.AddEditContextDataAnnotationsValidation(ValidateForm, Provider); | ||
| _message = new ValidationMessageStore(CurrentEditContext); | ||
| AddEditContextDataAnnotationsValidation(); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// 手动验证表单方法 | ||
| /// </summary> | ||
| /// <returns></returns> | ||
| internal bool Validate() => CurrentEditContext.Validate(); | ||
|
|
||
| private void AddEditContextDataAnnotationsValidation() | ||
| { | ||
| CurrentEditContext.OnValidationRequested += OnValidationRequested; | ||
| CurrentEditContext.OnFieldChanged += OnFieldChanged; | ||
| } | ||
|
|
||
| private void RemoveEditContextDataAnnotationsValidation() | ||
| { | ||
| CurrentEditContext.OnValidationRequested -= OnValidationRequested; | ||
| CurrentEditContext.OnFieldChanged -= OnFieldChanged; | ||
| } | ||
|
|
||
| private void OnValidationRequested(object? sender, ValidationRequestedEventArgs args) | ||
| { | ||
| _ = ValidateModel(CurrentEditContext, _message, Provider); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue (bug_risk): Asynchronous validation is not awaited, which may cause race conditions. ValidateModel and ValidateField are async but not awaited, which may lead to out-of-order validation or missed exceptions. Make the event handlers async and await these calls for correct execution. |
||
| } | ||
|
|
||
| private void OnFieldChanged(object? sender, FieldChangedEventArgs args) | ||
| { | ||
| _ = ValidateField(CurrentEditContext, _message, args.FieldIdentifier, Provider); | ||
| } | ||
|
|
||
| private async Task ValidateModel(EditContext editContext, ValidationMessageStore messages, IServiceProvider provider) | ||
| { | ||
| var validationContext = new ValidationContext(editContext.Model, provider, null); | ||
| var validationResults = new List<ValidationResult>(); | ||
| await ValidateForm.ValidateObject(validationContext, validationResults); | ||
|
|
||
| messages.Clear(); | ||
| foreach (var validationResult in validationResults.Where(v => !string.IsNullOrEmpty(v.ErrorMessage))) | ||
| { | ||
| foreach (var memberName in validationResult.MemberNames) | ||
| { | ||
| if (!string.IsNullOrEmpty(memberName)) | ||
| { | ||
| messages.Add(editContext.Field(memberName), validationResult.ErrorMessage!); | ||
| } | ||
| } | ||
| } | ||
| editContext.NotifyValidationStateChanged(); | ||
| } | ||
|
|
||
| private async Task ValidateField(EditContext editContext, ValidationMessageStore messages, FieldIdentifier field, IServiceProvider provider) | ||
| { | ||
| // 获取验证消息 | ||
| var validationResults = new List<ValidationResult>(); | ||
| var validationContext = new ValidationContext(field.Model, provider, null) | ||
| { | ||
| MemberName = field.FieldName, | ||
| DisplayName = field.GetDisplayName() | ||
| }; | ||
|
|
||
| await ValidateForm.ValidateFieldAsync(validationContext, validationResults); | ||
|
|
||
| messages.Clear(field); | ||
| messages.Add(field, validationResults.Where(v => !string.IsNullOrEmpty(v.ErrorMessage)).Select(result => result.ErrorMessage!)); | ||
|
|
||
| editContext.NotifyValidationStateChanged(); | ||
| } | ||
|
|
||
| private void Dispose(bool disposing) | ||
| { | ||
| if (disposing) | ||
| { | ||
| RemoveEditContextDataAnnotationsValidation(); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// <inheritdoc/> | ||
| /// </summary> | ||
| public void Dispose() | ||
| { | ||
| Dispose(true); | ||
| GC.SuppressFinalize(this); | ||
| } | ||
| } | ||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: Initialization of _message may be redundant due to OnInitialized logic.
Since _message is always set in OnInitialized, consider making it non-nullable and initializing it there, or use late initialization to prevent null reference confusion.
Suggested implementation:
You must ensure that
_messageis always initialized in theOnInitializedmethod (or wherever the initialization logic is guaranteed to run before use). For example:Remove any redundant initializations of
_messageelsewhere in the class.