如何在.NET Core中设置ConvertEmptyStringToNull默认值为false
ASP.NET Core 全局设置空字符串不自动转Null实现方案
原有实现失效原因
你之前编写的自定义元数据提供器存在两个核心问题:
- 仅重写了
GetMetadataForType方法,该方法仅返回类型本身的元数据,模型绑定、表单解析实际依赖的属性级元数据由CreatePropertyDetails方法生成,完全没有走到你设置ConvertEmptyStringToNull = false的逻辑。 - 重写逻辑中手动创建了
DisplayMetadataProviderContext,跳过了基类读取属性上标注的[DisplayFormat]等特性的流程,导致手动给字段加特性也会失效。
正确实现步骤
1. 编写自定义模型元数据提供器
重写创建类型元数据、属性元数据的两个核心方法,在基类生成的元数据基础上修改默认值,不覆盖显式标注的特性配置:
public class EmptyStringAllowedModelMetadataProvider : DefaultModelMetadataProvider { public EmptyStringAllowedModelMetadataProvider(ICompositeMetadataDetailsProvider detailsProvider) : base(detailsProvider) { } public EmptyStringAllowedModelMetadataProvider(ICompositeMetadataDetailsProvider detailsProvider, IOptions<MvcOptions> optionsAccessor) : base(detailsProvider, optionsAccessor) { } protected override ModelMetadata CreateTypeDetails(ModelMetadataIdentity key) { var metadata = base.CreateTypeDetails(key); // 为string类型本身设置默认值 if (metadata.ModelType == typeof(string)) { metadata.DisplayMetadata.ConvertEmptyStringToNull = false; } return metadata; } protected override ModelMetadata CreatePropertyDetails(ModelMetadataIdentity key) { var metadata = base.CreatePropertyDetails(key); // 仅针对string类型属性修改默认值 if (metadata.ModelType == typeof(string)) { // 检查属性是否显式标注了DisplayFormatAttribute,有则保留特性配置,无则使用默认值false var hasExplicitDisplayFormat = metadata.Attributes.PropertyAttributes .Any(attr => attr is DisplayFormatAttribute); if (!hasExplicitDisplayFormat) { metadata.DisplayMetadata.ConvertEmptyStringToNull = false; } } return metadata; } }
2. 注册自定义提供器替换默认实现
在Program.cs中(.NET 6+ 顶级语句模板),注册完MVC相关服务后,替换容器中默认的IModelMetadataProvider实例:
var builder = WebApplication.CreateBuilder(args); // 原有服务注册,根据项目实际场景选择对应方法:AddRazorPages/AddControllers/AddControllersWithViews builder.Services.AddControllersWithViews(); // 替换默认模型元数据提供器 builder.Services.AddSingleton<IModelMetadataProvider>(sp => { var compositeDetailsProvider = sp.GetRequiredService<ICompositeMetadataDetailsProvider>(); var mvcOptions = sp.GetRequiredService<IOptions<MvcOptions>>(); return new EmptyStringAllowedModelMetadataProvider(compositeDetailsProvider, mvcOptions); }); var app = builder.Build(); // 后续中间件配置保持原有逻辑即可
如果是使用Startup.cs的旧版.NET Core 3.1/.NET 5项目,在ConfigureServices方法中添加上述注册逻辑即可。
补充说明
- 该实现仅修改全局默认行为,如果你需要给特定字段开启空字符串转null,只需要在对应字段上显式标注
[DisplayFormat(ConvertEmptyStringToNull = true)],显式配置优先级高于全局默认。 - 该方案兼容ASP.NET Core 3.1到.NET 8的所有版本,不需要修改现有模型类的代码,所有string类型的字段、参数都会默认保留空字符串,不会自动转换为null。
内容的提问来源于stack exchange,提问作者TeamDman
相关产品推荐
相关产品推荐

