tags:

views:

338

answers:

1

Hey All,

I've been using several different tuts in order to build a LINQ-to-LDAP model. I've just about got it complete, but I'm running into some issues trying to bind the data returned to a class.

I do the reverse part by assigning custom attributes to the properties of the class that are the actual names of the database fields.

Here is an example of the class, as well as the custom attribute (the DirectorySchemaAttribute and DirectoryRootAttribute implementations are not included... those pieces are working correctly):

[DirectorySchema("C4User"), DirectoryRoot("o=c4, ou=users")]
class User
{
    [DirectoryAttribute("cn")]
    public string Username { get; set; }

    [DirectoryAttribute("userpassword")]
    public string Password { get; set; }

    [DirectoryAttribute("C4-Parent")]
    public string Parent { get; set; }
}


/// <summary>
/// Specifies the underlying attribute to query for in the directory.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class DirectoryAttributeAttribute : Attribute
{
    private string attribute;
    private DirectoryAttributeType type;

    /// <summary>
    /// Creates a new attribute binding attribute for a entity class field or property.
    /// </summary>
    /// <param name="attribute">Name of the attribute to query for.</param>
    public DirectoryAttributeAttribute(string attribute)
    {
        this.attribute = attribute;
        this.type = DirectoryAttributeType.Ldap;
    }

    /// <summary>
    /// Creates a new attribute binding attribute for a entity class field or property.
    /// </summary>
    /// <param name="attribute">Name of the attribute to query for.</param>
    /// <param name="type">Type of the underlying query source to get the attribute from.</param>
    public DirectoryAttributeAttribute(string attribute, DirectoryAttributeType type)
    {
        this.attribute = attribute;
        this.type = type;
    }

    /// <summary>
    /// Name of the attribute to query for.
    /// </summary>
    public string Attribute
    {
        get { return attribute; }
        set { attribute = value; }
    }

    /// <summary>
    /// Type of the underlying query source to get the attribute from.
    /// </summary>
    public DirectoryAttributeType Type
    {
        get { return type; }
        set { type = value; }
    }
}

So, I am populating my attributes for my LDAP Search with the Property's DirectoryAttributeAttribute::Name value. If it's not specified, then I just use the Property's Type name. So in essence, User.Username maps to "cn" and so forth.

I'm wondering what the best way is to do the reverse. So if I get a LDAP result back that contains a field named "cn" how do I find the property that has a DirectoryAttributeAttribute.Name that equals "cn". I am working on a foreach that gets the custom attributes for each property, but then I have to run that foreach for every field in the result set :( Kind of cumbersome. Can anyone think of a better way to do this?

Here is the code for the function that determines the field name that a property is mapped to:

private string GetFieldName(System.Reflection.MemberInfo member)
{
    DirectoryAttributeAttribute[] da = member.GetCustomAttributes(typeof(DirectoryAttributeAttribute), false) as DirectoryAttributeAttribute[];
    if (da != null && da.Length != 0)
    {
        if (da[0].Type == DirectoryAttributeType.ActiveDs)
            throw new InvalidOperationException("Can't execute query filters for IADs* properties.");
        else
            return da[0].Attribute;
    }
    else
        return member.Name;
}

Thanks, Chris

+1  A: 

Are you aware of "LINQ to Active Directory" ?? Check it out on Codeplex.

That might be a good starting point.

Marc

marc_s
Nice. The tuts I was looking at were actually written by the same person that posted the classes. It's helpful to have all the code now. Still having some difficulty making it support LDAP (rather than AD), but your post resolved my original question. Thanks!!
regex