Wednesday, November 24, 2010

LINQ To LDAP: Referential Integrity

I'm using the Northwind sample database to populate employees in Lightweight Directory Services.  I ran into an issue when trying to populate managers.  I incorrectly assumed that I could add employees in any order as long as I had a well formatted distinguished name for the manager.  Apparently some reference checking was being done behind the scenes for manager because I was getting a constraint error.  So a little refactoring and everything works!  Also, if no value exists for referenced entries, you can't just supply a null and call it good.  You have to opt out of sending that value or you'll get a null value error.

private void AddEmployee(LdapConnection connection, Employee employee)
{
    var distinguishedName = "CN=" + 
        employee.FirstName + " " + employee.LastName + 
        ",CN=Users,CN=Employees,DC=Northwind,DC=local";

    addedEmployees.Add(employee.EmployeeID, distinguishedName);

    string managerDistinguishedName = 
        employee.Manager == null 
            ? null
            : addedEmployees[employee.Manager.EmployeeID];

    List<DirectoryAttribute> attributes =
        new List<DirectoryAttribute>
            {
                new DirectoryAttribute("employeeID", employee.EmployeeID.ToString()),
                new DirectoryAttribute("sn", employee.LastName),
                new DirectoryAttribute("givenName", employee.FirstName),
                new DirectoryAttribute("comment", employee.Notes),
                new DirectoryAttribute("telephoneNumber", employee.HomePhone),
                new DirectoryAttribute("photo", employee.Photo),
                new DirectoryAttribute("title", employee.Title),
                new DirectoryAttribute("street", employee.Address),
                new DirectoryAttribute("l", employee.City),
                new DirectoryAttribute("c", employee.Country),
                new DirectoryAttribute("postalCode", employee.PostalCode)
            };
    if (!string.IsNullOrEmpty(managerDistinguishedName))
    {
        attributes.Add(
            new DirectoryAttribute("manager", managerDistinguishedName));
    }

    AddRequest addRequest = new AddRequest(distinguishedName, "user");
    addRequest.Attributes.AddRange(attributes.ToArray());
    connection.SendRequest(addRequest);

    if (employee.Employees.Any())
    {
        foreach (var subordinate in employee.Employees)
        {
            AddEmployee(connection, subordinate);
        }
    }
}

Tuesday, November 23, 2010

LINQ To LDAP

So big side step from my Mad Media Manager series.  Linq to LDAP has been an interest of mine since I found Bart De Smet's awesome Linq to AD.  I downloaded the source and started adding functionality that I thought should be there.  That worked pretty well for a while, but I eventually hit a wall when I wanted to add support for collection Contains operations so that I could do something like this
List<string> strings = new List<string>{"a", "b", "c"};
Expression<Func<MappedObject, bool> expression = 
     e => strings.Contains(e.SomeProperty);
and get a filter that does an “or equal” against the contents of the list.  There are workarounds to supporting this like creating the or condition dynamically, but I felt that I should be able to support it within the framework.  I’m aware that Bart is currently rewriting Linq to AD to support things like this, but I figured I’d take a stab at it myself and learn a lot about Linq and LDAP in the process.  So armed with Matt Warren's blog series I set out to write my own.