Introduction
Writing queries using Lightweight Directory Access Protocol (LDAP) has always been challenging, especially when you are not used to the LDAP syntax. The inclusion of the System.DirectoryServices
namespaces in the .NET framework made writing code for LDAP libraries a lot easier than with the traditional Active Directory Services Interfaces (ADSI) in non-managed languages. However, search functions in this namespaces such as the DirectorySearcher
class still relies on the ability of the programmer to write LDAP queries properly, thus leaving the fate of a well formatted query on the hands of the runtime.
A More Structured Solution
After analyzing and looking for a more structured way of writing these types of queries, I found a very compelling and clever way of writing function statements with conditional logic, which I found in Microsoft Excel. Excel’s way of writing functions consists of defining the logical operator as the function and the members inside the function on which they operate. For instance, consider the following query:
Select car from cars where (car.color = colors.red OR car.color = colors.blue)
AND car.make = makes.ford AND car.passengers > 5 AND car.model >= 2008
It can be also expressed as:
AND(
OR(
EQUALTO(car.color, colors.red),
EQUALTO(car.color, colors.blue)),
EQUALTO(car.make, makes.ford),
GREATHERTHAN(car.passengers, 5),
OR(
GREATHERTHAN(car.model, 2008),
EQUALTO (car.model, 2008))
In LDAP, the query would be as follows:
(&( |((color=red)(color=blue))(make=ford)(passengers>5)(model>=2008) ))
You can see how similar the last two expressions are.
Search Criteria
The first thing we need is a helper class to define expressions using syntax like the above. The SearchCriteria
class easily allows to define queries of this type, as defined below:
public class SearchCriteria
{
public SearchCriteria<T>[] Criteria { get; set; }
public static AndCriteria And(params SearchCriteria<T>[] criteria)
public static OrCriteria Or(params SearchCriteria<T>[] criteria)
public static NotCriteria Not(SearchCriteria<T> criteria)
public static GreatherThanFunctionCriteria GreatherThan(T name, string value)
public static LessThanFunctionCriteria LessThan(T name, string value)
public static EqualToFunctionCriteria EqualTo(T name, string value)
public static ContainsFunctionCriteria Contains(T name, string value)
public static IsLikeFunctionCriteria IsLike(T name, string value)
}
Then, to define the car query from the example above, we have to define an enumeration for fields allowed for the element car
, as follows:
public enum Car { color, make, passengers, model, }
Typed LDAP
Here is how we express the query in managed code:
var expression = SearchCriteria<Car>.And(
SearchCriteria<Car>.Or(
SearchCriteria<Car>.EqualTo(Car.color, Colors.red.ToString()),
SearchCriteria<Car>.EqualTo(Car.color, Colors.blue.ToString())),
SearchCriteria<Car>.EqualTo(Car.make, Makes.ford.ToString()),
SearchCriteria<Car>.GreatherThan(Car.passengers, "5"),
SearchCriteria<Car>.Or(
SearchCriteria<Car>.GreatherThan(Car.model, "2008"),
SearchCriteria<Car>.EqualTo(Car.model, "2008")));
Once we have a criteria object, we can pass that to the LdapBuilder
engine, which is another static class with one method:
public static string GetLdap(SearchCriteria criteria)
...
string ldapQuery = LdapBuilder<Car>.GetLdap(expression);
Then, invoking this method will dynamically call the proper routines that will generate a string representing a well formed LDAP query, that simple!
The Sample Code
In the sample code, you will find a fully functional version of this engine along with the implementation of the car example used in this article. Enjoy it :)
Born and built for Software Development. Eager to develop systems that drive business and human intelligence to the next level. Love Artificial Intelligence and have abundant experience in developing systems with a large user base. I know more than just how to write code that compiles. I can produce software that is fast, reliable, well-tested, secure, maintainable, globalizable, and on down the list of attributes of high-quality code.