0

I've got a some problem/question about MetadataType. I've got DLL helper-project for data access from MS SQL Server using LinqToSQL. I've also need to add a metadata for a generated class ClientInfoView. I've done it following way:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;

namespace DataAPI.LINQToSQL
{
    [MetadataType(typeof(ClientInfoViewMetaData))]
    public partial class ClientInfoView
    {
        internal sealed class ClientInfoViewMetaData
        {
            [Category("Main Data"), DisplayName("Client ID")]
            public int ID { get; set; }

            [Category("Main Data"), DisplayName("Login")]
            public string Login { get; set; }

            ...
        }
    }
}

But when I checked the attributes in runtime, I've found that ClientInfoView hasn't got any attributes.

Can you please help me to find a mistake?

shaddow
  • 107
  • 1
  • 1
  • 12
  • Have you tried placing ClientInfoViewMetaData outside ClientInfoView or declared the attribute as [MetadataType(typeof(ClientInfoView.ClientInfoViewMetaData))] ? – Rameez Ahmed Sayad Jul 26 '13 at 05:37
  • Yes I've tried to do it but result was the same =( – shaddow Jul 26 '13 at 05:41
  • Can you paste the code for how you're checking whether the attribute exists? – Rameez Ahmed Sayad Jul 26 '13 at 05:43
  • I check it in debug by typeof(ClientInfoView).GetProperty("ID").CustomAttributes. It shows me just LinqToSql attributes such as Storage, DBType and so on. – shaddow Jul 26 '13 at 05:50
  • The only thing I can find different on most examples is the modifier level . I know you're using internal and sealed based on the rules of Metadatatype attribute. Maybe try with just public and check – Rameez Ahmed Sayad Jul 26 '13 at 05:55
  • I've made ClientInfoViewMetaData public and moved it outside ClientInfoView class, but it didn't help =(. – shaddow Jul 26 '13 at 06:01
  • I think you can ask a separate question for accessing attributes of properties of a custom class. – Rameez Ahmed Sayad Jul 26 '13 at 10:49
  • check this this out , i already answered this question here http://stackoverflow.com/a/24757520/3050647 – elia07 Jul 15 '14 at 12:12

3 Answers3

3

because metadatatype is not for such porposes but you can use this method

private bool PropertyHasAttribute<T>(string properyName, Type attributeType)
    {
        MetadataTypeAttribute att = (MetadataTypeAttribute)Attribute.GetCustomAttribute(typeof(T), typeof(MetadataTypeAttribute));
        if (att != null)
        {
            ;
            foreach (var prop in Type.GetType(att.MetadataClassType.UnderlyingSystemType.FullName).GetProperties())
            {
                if (properyName.ToLower() == prop.Name.ToLower() && Attribute.IsDefined(prop,attributeType))
                    return true;
            }
        }
        return false;
    }

and you can use like this

bool res = PropertyHasAttribute<ClientInfoView>("Login", typeof(DisplayAttribute))

this tell you that the class property login has or has not displayattribute , but if you need to findout attribute Value you can use Attribute.GetCustomAttribute method and cast it to your selected attribute like display attribute and read Name property by .Name :)

Mark Schultheiss
  • 32,614
  • 12
  • 69
  • 100
elia07
  • 322
  • 2
  • 7
  • 1
    I think that your if inside foreach should be `if (properyName.ToLower() == prop.Name.ToLower() && Attribute.IsDefined(prop,attributeType))`. Notice propertyName changed to prop.Name. – prinkpan Feb 17 '19 at 15:48
1

To give some part of the answer , you can check ClientInfoView has got attributes. Some small demo that worked for me. Still trying to find why I can't access those attributes in ClientInfoViewMetaData individual properties

    static void Main(string[] args)
    {
        TypeDescriptor.AddProviderTransparent(
        new AssociatedMetadataTypeTypeDescriptionProvider(typeof(ClientInfoView), typeof(ClientInfoViewMetaData)), typeof(ClientInfoView));
        ClientInfoView cv1 = new ClientInfoView() { ID = 1 };
        var df = cv1.GetType().GetCustomAttributes(true);
        var dfd = cv1.ID.GetType().GetCustomAttributes(typeof(DisplayNameAttribute), true);
        var context = new ValidationContext(cv1, null, null);
        var results = new List<ValidationResult>();
        var isValid = Validator.TryValidateObject( cv1,context, results, true);
    }
}

    [MetadataType(typeof(ClientInfoViewMetaData))]
    public partial class ClientInfoView
    {
        public int ID { get; set; }
        public string Login { get; set; }
    }

public class ClientInfoViewMetaData
{        
    [Required]
    [Category("Main Data"), DisplayName("Client ID")]
    public int ID { get; set; }

    [Required]
    [Category("Main Data"), DisplayName("Login")]
    public string Login { get; set; }

}
Rameez Ahmed Sayad
  • 1,300
  • 6
  • 16
  • 29
0

Or you can use this extension method based on elia07 answer:

<System.Runtime.CompilerServices.Extension>
Public Function HasAttribute(Of TABLEENTITY, ATTRTYPE)(md As ModelMetadata) As Boolean
    Dim properyName As String = md.ContainerType.GetProperty(md.PropertyName).ToString()

    Dim att As MetadataTypeAttribute = DirectCast(Attribute.GetCustomAttribute(GetType(TABLEENTITY), GetType(MetadataTypeAttribute)), MetadataTypeAttribute)
    If att IsNot Nothing Then
        For Each prop In Type.[GetType](att.MetadataClassType.UnderlyingSystemType.FullName).GetProperties()
            If properyName.ToLower() = prop.Name.ToLower() AndAlso Attribute.IsDefined(prop, GetType(ATTRTYPE)) Then
                Return True
            End If
        Next
    End If

    Return False
End Function

A sample:

 Dim md As ModelMetadata = ...
 Dim isReadOnly As Boolean = md.HasAttribute(Of Cikkek, ReadOnlyFW)
Mark Schultheiss
  • 32,614
  • 12
  • 69
  • 100
SZL
  • 805
  • 8
  • 12