Свойства динамического отображения ASP.NET Core 2.1 на основе конфигурации из БД - PullRequest
0 голосов
/ 06 декабря 2018

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