我们有一个非常重要的要求,即同一个视图模型(JournalVoucher)可以具有许多“类型”(由用户配置),并且对于每个“类型”,JournalVoucher中的属性将具有不同的显示名称和验证规则,所有来自数据库中用户定义的配置。例如,在销售凭单中,“代理”属性的显示名称为“客户”,在购买凭单中,显示名称为“供应商”,依此类推。
经过一番研究,我无意间偶然发现了一个看起来过于简单以至于无法实现的解决方案,但到目前为止它仍然有效。我想知道是否有更多经验的人可以看看我是否做对了。也许其他开发人员也可以从代码中受益。
想法是从DefaultModelMetadataProvider
继承并像这样覆盖CreatePropertyDetails
:
public class CustomModelMetadataProvider : DefaultModelMetadataProvider
{
private readonly IMyContext _context;
public CustomModelMetadataProvider(ICompositeMetadataDetailsProvider detailsProvider, IMyContext context) : base(detailsProvider)
{
_context = context;
}
public CustomModelMetadataProvider(ICompositeMetadataDetailsProvider detailsProvider, IOptions<MvcOptions> optionsAccessor, IMyContext context) : base(detailsProvider, optionsAccessor)
{
_context = context;
}
protected override DefaultMetadataDetails[] CreatePropertyDetails(ModelMetadataIdentity key)
{
// Call the base implementation
var propsDetails = base.CreatePropertyDetails(key);
// If the model type is our dynamic entity
if (key.ModelType == typeof(JournalVoucher))
{
// Loop over the properties
foreach (var propDetails in propsDetails)
{
// If the property is one of our dynamic properties
string propertyName = propDetails.Key.Name;
if (propertyName == nameof(JournalVoucher.Agent))
{
// Set the display metadata passing a Func that dynamically
// determines the display name by calling a custom service that
// we inject in the constructor, the service may call
// the database or rely on info from the HTTP Context
propDetails.DisplayMetadata = new DisplayMetadata
{
// Dynamic display name!!
DisplayName = () => _context.GetJournalVoucherPropertyDisplayName(propertyName)
};
}
}
}
return propsDetails;
}
}
当然,您必须在Startup.cs中注册此实现:
services.AddSingleton<IMyContext, MyContext>();
services.AddSingleton<IModelMetadataProvider, CustomModelMetadataProvider>();