如何在MVC运行时自定义Display和Required属性



我想在razor视图中有一个动态标签的模型,该模型在运行时设置,但基于使用字符串格式的资源文件中的字符串。

假设我有一个简单的模型只有一个属性

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}

我想在razor视图

中做这样的操作
@Html.LabelFor(m => m.Property1, "xyz", new { @class = "control-label col-sm-4" })

和结果视图将显示字段标签为'xyz',值'xyz'也将显示在从服务器模型验证返回的验证消息中。

我一直在寻找各种方法来做到这一点,没有运气。我已经研究过重写DisplayAttribute,但这是一个密封类。

我还研究了重写DisplayName属性,但这并没有得到正确地与所需的验证消息。另外,我不确定如何将动态文本注入到属性中,我认为这需要在属性构造函数中完成。

我还考虑过编写自定义DataAnnotationsModelMetadataProvider,但看不到使用它来实现我想要的东西的方法。这可能是由于我缺乏编码技能。

'xyz'字符串将来自web中的设置。不需要在LabelFor命令中注入,但如果更有意义的话,可以在其他地方注入。

如果有人能给我一些线索,告诉我如何才能做到这一点,那就太好了。

我发现了这篇文章

替换DataAnnotationsModelMetadataProvider并操作返回的ModelMetadata是否有效

使我得出如下解决方案:

我在我的web配置中添加了一个自定义部分

  <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;
    }
}

然后我编写了一个自定义元数据提供程序,它根据翻译后的版本修改displayname

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 helper,没有做任何修改。

资源文件如下所示

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:    

相关内容

  • 没有找到相关文章

最新更新