簡體   English   中英

我可以在同一個字段上多次使用IMetadataAware屬性嗎?

[英]Can I use an IMetadataAware attribute multiple times on the same field?

我有不同的人應該看到不同名稱的字段。

例如,假設我有以下用戶類型:

public enum UserType {Expert, Normal, Guest}

我實現了一個IMetadataAware屬性:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class DisplayForUserTypeAttribute : Attribute, IMetadataAware
{
    private readonly UserType _userType;

    public DisplayForUserTypeAttribute(UserType userType)
    {
        _userType = userType;
    }

    public string Name { get; set; }

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        if (CurrentContext.UserType != _userType)
            return;
        metadata.DisplayName = Name;
    }
}

我的想法是,我可以根據需要覆蓋其他值,但是當我不這樣做時,可以使用默認值。 例如:

public class Model
{
    [Display(Name = "Age")]
    [DisplayForUserType(UserType.Guest, Name = "Age (in years, round down)")]
    public string Age { get; set; }

    [Display(Name = "Address")]
    [DisplayForUserType(UserType.Expert, Name = "ADR")]
    [DisplayForUserType(UserType.Normal, Name = "The Address")]
    [DisplayForUserType(UserType.Guest, Name = "This is an Address")]
    public string Address { get; set; }
}

問題是當我有多個相同類型的屬性時, DataAnnotationsModelMetadataProvider只為第一個屬性運行OnMetadataCreated
在上面的示例中, Address只能顯示為“Address”或“ADR” - 其他屬性永遠不會執行。

如果我嘗試使用不同的屬性 - DisplayForUserTypeDisplayForUserType2DisplayForUserType3 ,一切都按預期工作。

我在這里做錯了嗎?

我知道我在這個派對上有點遲了但是我正在尋找同樣問題的答案而無法在網上找到它。 最后我自己解決了。

簡而言之,您可以擁有在同一字段/屬性上實現IMetadataAware接口的多個相同類型的屬性。 您只需要記住在擴展它時覆蓋Attribute類的TypeId並將其替換為為每個派生屬性的每個實例提供唯一對象的東西。

如果不覆蓋派生屬性的TypeId屬性,那么該類型的所有屬性都將被視為相同,因為默認實現將屬性的運行時類型作為id返回。

因此,以下內容現在可以按預期工作:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class DisplayForUserTypeAttribute : Attribute, IMetadataAware
{
    private readonly UserType _userType;

    public DisplayForUserType(UserType userType)
    {
        _userType = userType;
    }

    public override object TypeId
    {
        get
        {
            return this;
        }
    }

    public string Name { get; set; }

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        if (CurrentContext.UserType != _userType)
            return;
        metadata.DisplayName = Name;
    }
}

您的實現沒有錯,但實現IMetadataAware任何屬性都是在創建元數據后由AssociatedMetadataProvider (以及任何派生類型)應用的。 要覆蓋默認行為,您可以實現自定義ModelMetadataProvider

這是另一種替代快速解決方案:

DisplayForUserType類中刪除IMetadataAware接口。

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
    public class DisplayForUserTypeAttribute : Attribute//, IMetadataAware
    {
        //your existing code...
    }

定義一個新的IMetadataAware屬性,該屬性將按UserType應用顯示邏輯,如下所示:

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
    public class ApplyDisplayForUserTypeAttribute : Attribute, IMetadataAware
    {
        private readonly string _property;
        public ApplyDisplayForUserTypeAttribute(string property)
        {
            this._property = property;
        }

        public void OnMetadataCreated(ModelMetadata metadata)
        {
            var attribues = GetCustomAttributes(metadata.ContainerType
                                                        .GetProperty(this._property), typeof(DisplayForUserTypeAttribute))
                                                        .OfType<DisplayForUserTypeAttribute>().ToArray();
            foreach (var displayForUserTypeAttribute in attribues)
            {
                displayForUserTypeAttribute.OnMetadataCreated(metadata);
            }
        }
    }

模型將是:

public class Model
    {
        [Display(Name = "Age")]
        [DisplayForUserType(UserType.Guest, Name = "Age (in years, round down)")]
        [ApplyDisplayForUserType("Age")]
        public string Age { get; set; }

        [Display(Name = "Address")]
        [DisplayForUserType(UserType.Expert, Name = "ADR Expert")]
        [DisplayForUserType(UserType.Normal, Name = "The Address Normal")]
        [DisplayForUserType(UserType.Guest, Name = "This is an Address (Guest)")]
        [ApplyDisplayForUserType("Address")]
        public string Address { get; set; }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM