Validation Blazor:使用同一模型验证多个表单

Validation Blazor:使用同一模型验证多个表单,validation,blazor-server-side,Validation,Blazor Server Side,我的Blazor应用程序在不同的组件中有两种形式。两种形式使用相同的视图模型。虽然模型相同,但组件中会显示不同的字段。例如,第一个组件的表单没有单价字段,但第二个组件的表单有单价字段。我使用一个简单的验证: [Required(ErrorMessage = "Unit Price is required.")] [Range(0.01, double.MaxValue, ErrorMessage = "Unit Price must be great

我的Blazor应用程序在不同的组件中有两种形式。两种形式使用相同的视图模型。虽然模型相同,但组件中会显示不同的字段。例如,第一个组件的表单没有单价字段,但第二个组件的表单有单价字段。我使用一个简单的验证:

    [Required(ErrorMessage = "Unit Price is required.")]
    [Range(0.01, double.MaxValue, ErrorMessage = "Unit Price must be greater than 0")]
    public double UnitPrice { get; set; }

不幸的是,当显示并提交第一个表单时,将验证缺少的字段,并且验证失败。有没有不拆分模型或使用自定义验证的方法来执行此操作?

我使用了条件验证,方法是从IValidatableObject派生我的视图模型并实现它:

public class MyViewModel : IValidatableObject
{
...
    public double UnitPrice { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var result = new List<ValidationResult>();

        if (StatusId >= (int)Models.Status.ReadyForReview) // my condition
        {
            if (UnitPrice == 0)
            {
                result.Add(new ValidationResult("Unit Price is required."));
            }
            else if (UnitPrice < 0)
            {
                result.Add(new ValidationResult("Unit Price must be greater than 0."));
            }
        }

        return result;
    }
}
公共类MyViewModel:IValidatableObject
{
...
公共双单价{get;set;}
公共IEnumerable验证(ValidationContext ValidationContext)
{
var result=新列表();
if(StatusId>=(int)Models.Status.ReadyForReview)//我的条件
{
如果(单价==0)
{
结果。添加(新的验证结果(“需要单价”);
}
否则如果(单价<0)
{
结果。添加(新的ValidationResult(“单价必须大于0”);
}
}
返回结果;
}
}
根据要求提供的示例:

public interface IForm
{
    int FormStatus { get; set; }
    // Your other fields that are always shared on this form...
}

public class Form1 : IForm
{
    public int FormStatus { get; set; }

    [Required(ErrorMessage = "Unit Price is required.")]
    [Range(0.01, double.MaxValue, ErrorMessage = "Unit Price must be greater than 0")]
    public decimal UnitPrice { get; set; }
}

public class Form2 : IForm
{
    public int FormStatus { get; set; }
    
    [Required]
    public string Name { get; set; } 
    // I made this up but it demonstrates the idea of encapsulating what differs.
}
您的共享Blazor组件类似于

// SharedFormFields.razor

<input type="text" @bind-Value="_form.FormStatus">

@code {
    [Parameter] private IForm Form { get; set; }
}
//SharedFormFields.razor
@代码{
[参数]私有形式{get;set;}
}
然后是您的消费组件/页面

@page "/Form1"

<EditContext Model=_form1>
   <SharedFormFields Form=_form1>
   <input type="number" @bind-Value="_form1.UnitPrice">
</EditContext

@code {
    private Form1 _form1 = new()
}
@page”/Form1

老实说,这似乎是一种设计的味道。如果是具有完全相同上下文的字段,可能是两个具有公共字段接口的视图模型。@BenSampica您能澄清您的建议吗?封装不同的内容。表单具有公共字段,这些字段可以通过接口表示。但是,每次使用该表单时,使用该表单的上下文都不同,这在您的情况下是正确的,因为您有不同的字段。随着时间的推移,这种形式继续发展,当你试图在一个类中协调两个不同的用例时,事情会变得很糟糕。@Ben Sampica,我明白了。你愿意把你的建议作为一个简单的例子,让我来做一个答案吗?非常感谢。我不会有任何共享组件,因为表单1的所有字段都是可编辑的,而表单2的所有字段都是只读的,除了2个特定于表单的字段。此外,在我的例子中,除了上面提到的两个字段外,几乎所有字段都是共享的。你的方法应该是一样的,对吗?另外,从表1派生出表2不是更好吗,因为表1的字段是表2字段的子集?我认为你走的是正确的道路。然而,我个人不会走继承路线,而是坚持实现接口,因为Form2是Form1的一个子类,会在两者之间引入意外的陷阱,因为它们仍然是单独的用例。表面上,它们通过属性共享共性,但一个用例涉及提交数据并使用属性对其进行验证,另一个用例只是数据的只读显示,没有验证。