Как настроить отображение и обязательные атрибуты во время выполнения в MVC

Я хотел бы иметь модель с динамической меткой в ​​виде бритвы, которая устанавливается во время выполнения, но основана на строке из файла ресурсов с использованием форматирования строки.

Допустим, у меня есть простая модель с одним свойством

public class Simple
{
    [Display(ResourceType = (typeof(Global)), Name = "UI_Property1")]
    [Required(ErrorMessageResourceType = (typeof(Global)), ErrorMessageResourceName = "ERROR_Required")]
    [StringLength(40, ErrorMessageResourceType = (typeof(Global)), ErrorMessageResourceName = "ERROR_MaxLength")]
    public string Property1{ get; set; }
}

И файл ресурсов имеет следующие строки

UI_Property1       {0}
ERROR_Required     Field {0} is required.
ERROR_MaxLength    Maximum length of {0} is {1}

и я хотел бы сделать что-то подобное в бритве

@Html.LabelFor(m => m.Property1, "xyz", new { @class = "control-label col-sm-4" })

и результирующее представление будет показывать метку поля как "xyz", а значение "xyz" также будет отображаться в сообщениях проверки, возвращаемых из проверки модели сервера.

Я искал различные способы сделать это без удачи. Я исследовал переопределение DisplayAttribute, но это закрытый класс.

Я также посмотрел на переопределение атрибута DisplayName, но это не правильно подобрано с необходимыми сообщениями проверки. Кроме того, я не был уверен, как вставить динамический текст в атрибут, который, как я полагаю, нужно будет сделать в конструкторе атрибута.

Я также рассмотрел написание пользовательского DataAnnotationsModelMetadataProvider, но не вижу способа использовать это для достижения того, что я хочу. Это может быть связано с моим отсутствием навыков кодирования.

Строка 'xyz' будет исходить из настройки в файле web.config, и ее не нужно вводить в команде LabelFor, но ее можно вводить где-то еще, если это будет иметь больше смысла.

Если бы кто-нибудь мог дать мне подсказку о том, как я мог бы достичь этого, это было бы здорово.

1 ответ

Решение

Я нашел этот пост

Допустимо ли заменить DataAnnotationsModelMetadataProvider и манипулировать возвращенными ModelMetadata

что привело меня к решению следующим образом:

Я добавил пользовательский раздел в мою веб-конфигурацию

  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="labelTranslations" type="AttributeTesting.Config.LabelTranslatorSection" />
    ... other sections here
  </configSections>

  <labelTranslations>
    <labels>
      <add label=":Customer:" translateTo="Customer Name" />
      <add label=":Portfolio:" translateTo="Portfolio Name" />
      <add label=":Site:" translateTo="Site Name" />
    </labels>
  </labelTranslations>

Класс для обработки пользовательского раздела загружает метки, которые должны быть переведены

public class LabelElement : ConfigurationElement
{
    private const string LABEL = "label";
    private const string TRANSLATE_TO = "translateTo";

    [ConfigurationProperty(LABEL, IsKey = true, IsRequired = true)]
    public string Label
    {
        get { return (string)this[LABEL]; }
        set { this[LABEL] = value; }
    }

    [ConfigurationProperty(TRANSLATE_TO, IsRequired = true)]
    public string TranslateTo
    {
        get { return (string)this[TRANSLATE_TO]; }
        set { this[TRANSLATE_TO] = value; }
    }

}

[ConfigurationCollection(typeof(LabelElement))]
public class LabelElementCollection : ConfigurationElementCollection
{
    protected override ConfigurationElement CreateNewElement()
    {
        return new LabelElement();
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((LabelElement)element).Label;
    }

    public LabelElement this[string key]
    {
        get
        {
            return this.OfType<LabelElement>().FirstOrDefault(item => item.Label == key);
        }
    }
}

public class LabelTranslatorSection : ConfigurationSection
{
    private const string LABELS = "labels";

    [ConfigurationProperty(LABELS, IsDefaultCollection = true)]
    public LabelElementCollection Labels
    {
        get { return (LabelElementCollection)this[LABELS]; }
        set { this[LABELS] = value; }
    }
}

Затем переводчик использует пользовательский раздел для перевода данной метки в переведенную версию, если она существует, в противном случае он возвращает метку

public static class Translator
{
    private readonly static LabelTranslatorSection config =
        ConfigurationManager.GetSection("labelTranslations") as LabelTranslatorSection;

    public static string Translate(string label)
    {
        return config.Labels[label] != null ? config.Labels[label].TranslateTo : label;
    }
}

Затем я написал собственный поставщик метаданных, который изменяет отображаемое имя на основе переведенной версии.

public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(
                             IEnumerable<Attribute> attributes,
                             Type containerType,
                             Func<object> modelAccessor,
                             Type modelType,
                             string propertyName)
    {

        // Call the base method and obtain a metadata object.
        var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);

        if (containerType != null)
        {
            // Obtain informations to query the translator.
            //var objectName = containerType.FullName;
            var displayName = metadata.GetDisplayName();

            // Update the metadata from the translator
            metadata.DisplayName = Translator.Translate(displayName);
        }

        return metadata;
    }
}

после этого все это просто сработало, и ярлыки и сообщения проверки все использовали переведенные версии. Я использовал стандартные помощники LabelFor без каких-либо модификаций.

Файл ресурса выглядит так

ERROR_MaxLength   {0} can be no more than {1} characters long   
ERROR_Required    {0} is a required field   
UI_CustomerName   :Customer:    
UI_PortfolioName  :Portfolio:   
UI_SiteName       :Site:    
Другие вопросы по тегам