use*_*918 6 asp.net-core blazor-server-side
我有一个 Blazor 组件,其中包含一个人的姓名及其地址。我已将地址拆分出来,以便可以重复使用。我在人员和地址之间使用 2 路数据绑定,以确保数据传递到该地址并且人员可以接收地址更改。
但我无法获得工作验证。人员全名和地址行 1 不能为空。当我使用VaidationSummary时,它会正确报告两个字段不能为空。但是,当我使用ValidationMessage时,只有人员全名才会报告验证消息。我正在使用 Fluent 验证,但我认为问题是ValidationMessage在复杂类型中不会报告。
我认为这是因为地址行 1 ValidationMessage的 For() 属性与主表单(人员)数据模型中的字段名称不匹配。主数据模型将地址类作为“地址”,但地址组件将其作为“值”。但是,如果我要重用该组件,那么这种情况很可能会发生!
分离地址等组件似乎是一件合理的事情,并且表单上可能有多个地址对象(例如交付和计费),所以我只需要知道如何做到这一点。
有人这样做过吗?是否需要自定义 ValidationMessage 或者不同的 For() 实现?
感谢您对此的帮助。这是来源。
形式:
<EditForm Model=@FormData>
<FluentValidator/>
<ValidationSummary/>
<InputText @bind-Value=FormData.FullName />
<ValidationMessage For="@(() => FormData.FullName)"/>
<ComponentAddress @bind-Value=FormData.Address />
<input type="submit" value="Submit" class="btn btn-primary" />
</EditForm>
@code{
PersonDataModel FormData = new PersonDataModel();
}
Run Code Online (Sandbox Code Playgroud)
地址组件:
<InputText @bind-Value=Value.Address1 @onchange="UpdateValue" />
<ValidationMessage For="@(() => Value.Address1)" />
@code{
[Parameter] public AddressDataModel Value { get; set; }
[Parameter] public EventCallback<AddressDataModel> ValueChanged { get; set; }
protected async Task UpdateValue()
{
await ValueChanged.InvokeAsync(Value);
}
}
Run Code Online (Sandbox Code Playgroud)
人物模型:
public class PersonDataModel
{
[Required]
public string FullName { get; set; }
public AddressDataModel Address { get; set; }
public PersonDataModel()
{
Address = new AddressDataModel();
}
}
Run Code Online (Sandbox Code Playgroud)
地址型号:
public class AddressDataModel
{
[Required]
public string Address1 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
人员流利验证器:
public class PersonValidator : AbstractValidator<PersonDataModel>
{
public PersonValidator()
{
RuleFor(r => r.FullName).NotEmpty().WithMessage("You must enter a name");
RuleFor(r => r.Address.Address1).NotEmpty().WithMessage("You must enter Address line 1");
}
}
Run Code Online (Sandbox Code Playgroud)
小智 1
问题是ValidationContext验证组件的属性是组件的Value属性,而不是父页面正在使用的模型。
我一直在努力让组件验证工作起来,直到我使用应用于组件属性的另一个验证属性发现了一些技巧Value。验证时Value,我使用组件EditContext,它是通过级联参数设置的属性。我可以通过反射获取属性的名称,这意味着我可以获取正确的FieldIdentifier,通知该字段已更改,然后ValidationResult从父级的EditContext. 然后我可以返回相同的错误详细信息。
验证属性
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using ValueBinding.Shared;
namespace ValueBinding.Data.Annotations
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class MyValidationContextCheckAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
EditContext ec = null;
string propName = "NOT SET";
// My StringWrapper is basic component with manual Value binding
if (validationContext.ObjectInstance is MyStringWrapper)
{
var strComp = (MyStringWrapper)validationContext.ObjectInstance;
ec = strComp.ParentEditContext; // Uses Cascading Value/Property
propName = strComp.GetPropertyName();
}
if (ec != null)
{
FieldIdentifier fld = ec.Field(propName);
ec.NotifyFieldChanged(in fld);
// Validation handled in Validation Context of the correct field not the "Value" Property on component
var errors = ec.GetValidationMessages(fld);
if (errors.Any())
{
string errorMessage = errors.First();
return new ValidationResult(errorMessage, new List<string> { propName });
}
else
{
return null;
}
}
else if (typeof(ComponentBase).IsAssignableFrom(validationContext.ObjectType))
{
return new ValidationResult($"{validationContext.MemberName} - Validation Context is Component and not data class", new List<string> { validationContext.MemberName });
}
else
{
return null;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
成分
@using System.Linq.Expressions
@using System.Reflection
@using Data
@using Data.Annotations
<div class="fld" style="border-color: blue;">
<h3>@GetPropertyName()</h3>
<InputText @bind-Value=@Value />
<ValidationMessage For=@ValidationProperty />
<div class="fld-info">@HelpText</div>
</div>
@code {
[Parameter]
public string Label { get; set; } = "NOT SET";
[Parameter]
public string HelpText { get; set; } = "NOT SET";
[Parameter]
public Expression<Func<string>> ValidationProperty { get; set; }
private string stringValue = "NOT SET";
[MyValidationContextCheck]
[Parameter]
public string Value
{
get => stringValue;
set
{
if (!stringValue.Equals(value))
{
stringValue = value;
_ = ValueChanged.InvokeAsync(stringValue);
}
}
}
[Parameter]
public EventCallback<string> ValueChanged { get; set; }
[CascadingParameter]
public EditContext ParentEditContext { get; set; }
public string GetPropertyName()
{
Expression body = ValidationProperty.Body;
MemberExpression memberExpression = body as MemberExpression;
if (memberExpression == null)
{
memberExpression = (MemberExpression)((UnaryExpression)body).Operand;
}
PropertyInfo propInfo = memberExpression.Member as PropertyInfo;
return propInfo.Name;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1892 次 |
| 最近记录: |