У нас есть нетривиальное требование, чтобы одна и та же модель представления (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>();