Collection Class Usage

We need to know just a few basic things about using the value collection classes in order to be productive. Let's examine this from a task-centric perspective. In each of these examples, assume we have a DirectoryEntry called entry and a SearchResult called result pointing to the same object in the directory.

Getting Single Values

This is probably the thing we will do most often. Typically, we will either use the Value property or access the first element in the collection:

object name = entry.Properties["name"].Value; name = entry.Properties["name"][0]; name = result.Properties["name"][0];

Note that the first approach is slightly safer if we have not already checked for a null value, as the Value property will return null/Nothing. The other approaches will throw an exception if the attribute is null, as the array will not have a value at index 0.

Checking for Null Values

If we try to imagine an object in an LDAP directory as a row in a SQL database, the schema for the table would typically allow many null column values. The vast majority of attributes in most LDAP classes are optional and it is very common for objects to contain only a small fraction of the attributes allowed by the schema. This analogy is a little flimsy, and we explain why in the sidebar LDAP and Null Values, later in this chapter. However, it is useful for our purposes here.

As a result, we will be checking for null values frequently. This is just good defensive programming and will contribute greatly to the stability of our applications in production.

With PropertyValueCollection, we can do this by using the Value property:

if (entry.Properties["description"].Value != null) { //do something interesting }

An alternate approach is to check the Count property:

if (entry.Properties["description"].Count > 0) { //do something interesting }

Things change a bit with ResultPropertyValueCollection. Since it does not have a Value property, we cannot check it for a null value. This is also a situation where there are differences between versions 1.x and 2.0 of the framework. Namely, in version 1.x, a ResultPropertyValueCollection instance was not created if the attribute was not returned in the search, so checking a property like Count would generate a NullReferenceException. This behavior has changed in version 2.0, and a Result-PropertyValueCollection instance will be returned, making it safe to check the Count property without fear of an exception.

LDAP and Null Values

We are purposely being a little bit loose with the term "null" in our discussion. Unlike in the RDBMS world, where we have neat rows and columns that structure our data, the LDAP world does not correspond to this model exactly. If we consider an object to be a row, then the attributes are the columns in a table. If we check the intersection of any row and column, we expect either a value or null. However, this analogy breaks down a bit when we consider that null values do not really exist in LDAP. Either the object contains the attribute or it does not. If we compare it to the RDBMS world again, it would be as if each object was a row, and each row had different columns defined. It is not as if the object contained an attribute that we could find, and it contained a "null" value! The attribute simply does not exist, and from a developer's perspective, we infer this to mean it is null.

As such, when we say an attribute is null, we really mean that the attribute does not exist on the object. That our SDS objects return null for nonexistent attributes is only a result of our programming model.

Of course, it is less than ideal to have to remember how value collections will behave based on the version of the framework we are using, and it leads to fragile code. Instead, we should always check the ResultPropertyCollection or PropertyValueCollection first:

if (result.Properties.Contains("description")) { //do something interesting } if (entry.Properties.Contains("description")) { //do something interesting }

It turns out that since the Contains method works for both Result-PropertyCollection and PropertyCollection classes, it tends to be easier to use this method consistently without needing to remember the details of either class or the differences due to versions of the framework. For this reason, we generally recommend using the Contains method, as it will work well in all circumstances and scenarios.

Checking for Multiple Values

Many attributes in LDAP allow multiple values and the basic design of the value collections assumes that any attribute may contain multiple values. In order to find out if an attribute actually contains multiple values, we can use the Count property:

if (entry.Properties["memberOf"].Count > 1) { //do something interesting } if (result.Properties.Contains("memberOf")) { if (result.Properties["memberOf"].Count > 1) { //do something interesting } }

We would do something similar with a SearchResult/ResultPropertyValueCollection.

Another option is simply to enumerate the collection with foreach:

foreach (string groupDN in entry.Properties["memberOf"]) { //do something interesting } if (result.Properties.Contains("memberOf")) { foreach (string groupDN in result.Properties["memberOf"]) { //do something interesting } }

 

Using the Value Property

One of the primary differences between PropertyValueCollection and ResultPropertyValueCollection is that the former contains a Value property. The Value property does one of three different things when reading an attribute value.

For example, let's take the member attribute on the group class. It is defined as syntax 2.5.5.1, which is represented in .NET as System.String (see Table 6.1). It is defined in the schema as multivalued and optional. As such, the Value property might return null, a System.String, or an array of System.String objects, depending on whether the group has zero, one, or multiple members.

This makes the Value property especially useful for getting attribute values directly, as we have seen in the earlier examples and throughout the book. It can also be used for writing attribute values, where it is even more useful.

Категории