7

さまざまな人がさまざまな名前で表示する必要のあるフィールドがあります。

たとえば、次のユーザータイプがあるとします。

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「アドレス」または「ADR」としてのみ表示できます。他の属性は実行されません。

異なる属性を使用しようとすると、、、、、DisplayForUserTypeすべてDisplayForUserType2DisplayForUserType3期待どおりに機能します。

私はここで何か間違ったことをしていますか?

4

2 に答える 2

1

実装は間違っていませんが、実装する属性は、メタデータの作成後にAssociatedMetadataProvider(および派生型)IMetadataAwareによって適用されます。デフォルトの動作をオーバーライドするには、customを実装します。ModelMetadataProvider

別の簡単な解決策は次のとおりです。

クラスIMetadataAwareからインターフェイスを削除します。DisplayForUserType

    [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; }
    }
于 2013-03-05T17:48:44.193 に答える