.NET Core中如何实现自定义元数据提供器,按类型设置显示/编辑格式?
.NET Core中自定义模型元数据提供器(基于DefaultModelMetadataProvider)的实现问题
需求背景
需要实现一个继承自DefaultModelMetadataProvider的自定义模型元数据提供器,核心目的是根据数据类型为显示、编辑操作设置不同的日期格式。此前已有基于DataAnnotationsModelMetadataProvider的可行实现,现需移植到.NET Core并改用DefaultModelMetadataProvider。
原有可行实现(基于DataAnnotationsModelMetadataProvider)
public class ASLMetadataProvider : DataAnnotationsModelMetadataProvider { protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) { ModelMetadata modelMetadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName); // DisplayFormatAttribute不支持为显示和编辑设置不同格式,因此在这里处理 if (modelMetadata.DataTypeName == "Date") { modelMetadata.DisplayFormatString = DataFormatString.DateDisplay; modelMetadata.EditFormatString = DataFormatString.DateEdit; } return modelMetadata; } }
当前尝试及疑问
已将类改为继承DefaultModelMetadataProvider,并实现了两个调用基类构造函数的空构造函数:
public ASLMetadataProvider(ICompositeMetadataDetailsProvider detailsProvider) : base(detailsProvider) {} public ASLMetadataProvider(ICompositeMetadataDetailsProvider detailsProvider, IOptions<MvcOptions> optionsAccessor) : base(detailsProvider, optionsAccessor) {}
同时尝试重写GetMetadataForType等方法,但不确定该方案是否可行,也不清楚应该重写哪个方法,以及如何像之前的CreateMetadata那样获取并修改ModelMetadata。
已在Program.cs中完成注册(自定义方法能被正常调用):
builder.Services.AddSingleton<IModelMetadataProvider, ASLMetadataProvider>();
解决方案
方案一:自定义IMetadataDetailsProvider(推荐,符合.NET Core设计)
DefaultModelMetadataProvider依赖ICompositeMetadataDetailsProvider组装元数据,因此可以创建自定义的IDisplayMetadataProvider来处理日期格式设置,无需替换整个默认提供器:
public class DateDisplayMetadataProvider : IDisplayMetadataProvider { public void CreateDisplayMetadata(DisplayMetadataProviderContext context) { // 识别日期相关类型(含可空类型) var modelType = context.Key.ModelType; if (modelType == typeof(DateTime) || modelType == typeof(DateTime?) || modelType == typeof(DateOnly) || modelType == typeof(DateOnly?)) { context.DisplayMetadata.DisplayFormatString = DataFormatString.DateDisplay; context.DisplayMetadata.EditFormatString = DataFormatString.DateEdit; context.DisplayMetadata.DataTypeName = "Date"; } } }
注册方式(替换原有注册代码):
builder.Services.AddMvc(options => { options.ModelMetadataDetailsProviders.Add(new DateDisplayMetadataProvider()); });
方案二:重写DefaultModelMetadataProvider的CreateModelMetadata方法
如果坚持继承DefaultModelMetadataProvider,可以重写其核心的CreateModelMetadata方法来修改元数据:
public class ASLMetadataProvider : DefaultModelMetadataProvider { public ASLMetadataProvider(ICompositeMetadataDetailsProvider detailsProvider) : base(detailsProvider) { } public ASLMetadataProvider(ICompositeMetadataDetailsProvider detailsProvider, IOptions<MvcOptions> optionsAccessor) : base(detailsProvider, optionsAccessor) { } protected override DefaultModelMetadata CreateModelMetadata(ModelMetadataIdentity identity, ModelMetadataDetails details) { var metadata = base.CreateModelMetadata(identity, details); // 检查数据类型并设置对应格式 if (metadata.DataTypeName == "Date" || identity.ModelType == typeof(DateTime) || identity.ModelType == typeof(DateTime?) || identity.ModelType == typeof(DateOnly) || identity.ModelType == typeof(DateOnly?)) { metadata.DisplayFormatString = DataFormatString.DateDisplay; metadata.EditFormatString = DataFormatString.DateEdit; } return metadata; } }
注册方式保持原有代码即可:
builder.Services.AddSingleton<IModelMetadataProvider, ASLMetadataProvider>();
注意事项
- 直接判断模型类型(如
DateOnly、DateTime)比依赖DataTypeName更可靠,尤其是处理.NET 6+新增的DateOnly类型时。 - 方案一更轻量,符合.NET Core的扩展设计原则,优先推荐使用。
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

