You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 9 Blazor Server端DataAnnotations元数据失效问题排查

问题原因

Blazor Server的组件(如EditForm、DataAnnotationsValidator)并不依赖TypeDescriptor系统获取元数据,而是直接通过反射读取DataAnnotations特性,或者基于ASP.NET Core的ModelMetadata体系工作。你之前使用TypeDescriptor.AddProviderTransparent的方式仅适用于WinForms、ASP.NET Web Forms等旧技术栈,对Blazor完全无效,这就是元数据不生效的核心原因。

解决方案

方案1:使用分部类 + [MetadataType]特性(最简洁推荐)

由于EF Core Power Tools生成的AsphaltIndexPrice是分部类,你可以创建一个新的分部类文件,通过[MetadataType]特性关联元数据类,Blazor会自动识别元数据中的注解:

// 新建文件:AsphaltIndexPrice.Metadata.cs
using System.ComponentModel.DataAnnotations;

[MetadataType(typeof(AsphaltIndexPriceMetaData))]
public partial class AsphaltIndexPrice
{
    // 无需添加任何额外代码,仅用于关联元数据类
}

同时删除所有与TypeDescriptor相关的初始化代码(包括HMADBMetaDataInit方法和Program.cs中的调用),Blazor的DataAnnotationsValidator会自动读取元数据类中的[Display]、[Required]等特性。

方案2:自定义ModelMetadataProvider(无需修改分部类)

如果不想修改分部类,可以自定义一个元数据提供器,手动将元数据类的注解合并到目标类上:

using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using System.ComponentModel.DataAnnotations;

public class CustomMetadataProvider : DataAnnotationsModelMetadataProvider
{
    // 维护模型类与元数据类的映射关系
    private readonly Dictionary<Type, Type> _metadataMappings = new()
    {
        { typeof(AsphaltIndexPrice), typeof(AsphaltIndexPriceMetaData) }
    };

    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Type modelType, string propertyName)
    {
        // 如果当前模型类有对应的元数据类,合并属性注解
        if (_metadataMappings.TryGetValue(modelType, out var metadataType))
        {
            var metadataProperty = metadataType.GetProperty(propertyName);
            if (metadataProperty != null)
            {
                attributes = attributes.Concat(metadataProperty.GetCustomAttributes());
            }
        }
        return base.CreateMetadata(attributes, containerType, modelType, propertyName);
    }
}

然后在Program.cs中注册这个自定义提供器:

builder.Services.AddSingleton<IModelMetadataProvider, CustomMetadataProvider>();

// 后续的builder.Build()、app.Run()保持不变

方案3:使用FluentValidation(更灵活的验证方案)

如果需要更复杂的验证逻辑,可以使用FluentValidation替代DataAnnotations,它不需要依赖元数据类,直接编写验证规则:

  1. 安装NuGet包:FluentValidation.AspNetCore
  2. 编写验证规则:
using FluentValidation;

public class AsphaltIndexPriceValidator : AbstractValidator<AsphaltIndexPrice>
{
    public AsphaltIndexPriceValidator()
    {
        RuleFor(x => x.EffectiveDate)
            .NotEmpty().WithMessage("An Effective Date is required")
            .WithName("Effective Date");

        RuleFor(x => x.IndexPrice)
            .NotEmpty().WithMessage("An Index Price is required")
            .WithName("Price");
    }
}
  1. 在Program.cs注册验证器:
builder.Services.AddFluentValidationAutoValidation()
                .AddValidatorsFromAssemblyContaining<AsphaltIndexPriceValidator>();
验证步骤
  1. 确保页面的EditForm中包含对应验证组件:
<EditForm Model="@Model" OnValidSubmit="@HandleValidSubmit">
    <!-- 方案1/2使用 -->
    <DataAnnotationsValidator />
    <!-- 方案3使用 -->
    <!-- <FluentValidationValidator /> -->
    
    <div class="form-group">
        <label>@Html.DisplayNameFor(m => m.EffectiveDate)</label>
        <InputDate @bind-Value="@Model.EffectiveDate" />
        <ValidationMessage For="@(() => Model.EffectiveDate)" />
    </div>

    <!-- 其他表单字段 -->
    <button type="submit">Save</button>
</EditForm>
  1. 重启项目后,标签会显示自定义名称,验证时会触发自定义错误提示。

内容的提问来源于stack exchange,提问作者StuartV

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 15:55:19