使用自定义功能覆盖MVC模型显示名称注释

时间:2019-08-08 15:38:16

标签: c# asp.net-mvc asp.net-mvc-4 data-annotations modelstate

我使用以下方法从键值XML文件中进行读取。我传入了一个键,并返回了一个我以前在视图上显示的值。

public static class TextManager
{
    public static string GetValue(string key)
    {
        string returnVal = null; 
        XmlSerializer serializer = new XmlSerializer(typeof(Entries));
        string path = HttpContext.Current.Server.MapPath("/App_Data/text-key-value.xml");
        if (File.Exists(path))
        {
            Entries entries = (Entries)serializer.Deserialize(File.OpenRead(path));
            var entry = entries.Where(u => u.Key == key).FirstOrDefault();
            if (entry != null)
            {
                returnVal = entry.Value;
            }
        }
        return returnVal;
    }
}

基本上,我希望能够在模型类中使用此方法作为数据注释,该方法将直接从站点文本文件中提取并设置为显示名称属性。

例如我要替换

[Display(Name = "Reference Code")]
public string ReferenceCode { get; set; }

有了这个

[DisplaySiteText("ReferenceCodeKey")]
public string ReferenceCode { get; set; }

DisplaySiteText会将字符串引用“ ReferenceCodeKey”传递给GetValue方法,将该引用归档到文件中,然后将标准显示名属性设置为文件中的内容。

我该如何创建自己的自定义模型注释,过去我通过创建一个继承自ValidationAttribute的类来编写自定义验证注释,但是在这种情况下,我认为这样做不起作用。

3 个答案:

答案 0 :(得分:5)

您可以为此目的继承DisplayNameAttribute

public class DisplaySiteTextAttribute : DisplayNameAttribute
{
    private string _key;

    public DisplaySiteTextAttribute(string key)
    {
        _key = key;
    }

    public override string DisplayName
    {
        get
        {
            return TextManager.GetValue(_key);
        }
    }
}

答案 1 :(得分:4)

有几种自定义模型元数据的选项:

  • 自定义框架提供元数据的方式。 (创建ModelMedatadaProvider
  • 创建新的元数据属性。 (实施IMetadataAware
  • 修改现有属性。 (派生现有属性。)

第三个选项已在另一个答案中讨论。在这篇文章中,我将分享第一个和第二个选项。

选项1-自定义框架提供元数据的方式

您可以更改获取显示文本的逻辑,而无需更改属性。

实际上,ModelMetaDataProvider有责任获取模型的气象数据,包括属性的显示文本。因此,可以选择保留Display属性,而可以创建一个新的模型元数据提供程序,并从其他来源返回属性元数据。

为此,您可以通过从DataAnnotationsModelMetadataProvider派生来创建新的元数据提供程序。然后覆盖GetMetadataForProperty并调用base以获取元数据。然后,根据您的逻辑,通过从文本管理器读取内容来更改DisplayName

您还需要在App_Start中将新的元数据提供程序注册为ModelMetadataProviders.Current

using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;
public class MyCustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor,
        Type containerType,
        PropertyDescriptor propertyDescriptor)
    {
        var metadata = base.GetMetadataForProperty(modelAccessor, 
            containerType, propertyDescriptor);
        var display = propertyDescriptor.Attributes
            .OfType<DisplayAttribute>().FirstOrDefault();
        if (display != null)
        {
            metadata.DisplayName = TextManager.GetValue(display.Name);
        }
        return metadata;
    }
}

然后在Application_Start()中注册:

ModelMetadataProviders.Current = new MyCustomModelMetadataProvider();

有关更多信息,请查看ASP.NET MVC源代码中的DataAnnotationsModelMetadataProvider.cs源代码。

  

当您要更改为模型提供元数据的方式时,此方法很有用。例如,当您要从外部文件而不是从资源加载显示名称和描述时,而不更改现有属性。

选项2-创建新的元数据属性

用于创建可识别元数据的属性的另一种标准解决方案是创建属性并实现IMetadataAware接口。然后,在实现OnMetadataCreated时,您可以轻松设置metadata的属性。

这种方法不需要注册新的元数据提供者。默认元数据提供程序支持此方法,该方法可用于创建新的元数据感知属性:

using System;
using System.Web.Mvc;
public class CustomMetadataAttribure : Attribute, IMetadataAware
{
    public string Key { get; set; }
    public CustomMetadataAttribure(string key) => this.Key = key;
    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.DisplayName = TextManager.GetValue(this.Key);
    }
}
  

当您想扩展元数据属性并添加更多属性时,此方法很有用。例如,当您想添加一些属性来控制渲染时。您可以设置ModelMetadata属性或向其AdditionalValues字典中添加一些新值。

答案 2 :(得分:1)

也许您的DisplaySiteText属性可以继承自Display属性,并使用您的帮助器类来设置名称。像这样:

public class DisplaySiteTextAttribute : DisplayAttribute
{
    public DisplaySiteTextAttribute(string key)
    {
        Name = TextManager.GetValue(key);
    }
}