The data types in LDAP are defined by what are known as LDAP syntaxes. According to the LDAP specifications (see RFC 2252), the syntax describes the type of data that can be stored in the attribute and the format used to read and write to it via the LDAP API.
The Property Cache under the Hood
Those familiar with ADSI will recognize the RefreshCache methods being equivalent to the GetInfo and GetInfoEx methods on the IADs interface. Under the hood, RefreshCache pretty much invokes those methods directly. CommitChanges is also paired exactly with the Set-Info IADs method.
But how does the property cache actually work at the LDAP level? In order to fill the cache, the ADSI LDAP provider performs a base-level search on the object in question, with no attributes specified in the attribute list. When no attributes are specified, the default LDAP API behavior is to return all nonconstructed attributes. Constructed attributes must always be requested specifically. This is why we must use the version of RefreshCache that takes an array of strings as an argument.
Warning: Do Not Disable the Cache
SDS provides a mechanism for disabling the property cache by setting the UsePropertyCache property on the DirectoryEntry object to false. In this mode, each attribute is read as needed and changes are flushed to the directory immediately.
Do not use this feature. The property cache makes things significantly faster and generally makes our programming lives easier. Neither of us can remember a time when disabling the cache was even useful.
The syntax is defined by a combination of the LDAP syntax, which is defined as an Object Identifier (OID), and the OM syntax, which is an integer value.
Table 6.1 defines the syntaxes supported by Active Directory and ADAM.
Note that most of the LDAP types have their own OID, but a few share the same OID and differ only by OM syntax. Additionally, a few types share the same OM syntax, but differ by OID. It does not help our cause to try to explain this right now, so we will let that go for now.
We have to get through a few conversions to use these types in .NET. First, each LDAP data type has a corresponding ADSI data type used to represent it within the ADSI world. Next, each ADSI data type has a default COM data type that it will be converted to by clients using the automation-compliant APIs. Finally, each COM data type has a default marshaling behavior in .NET determined by the .NET COM interop layer.
Looking at Table 6.1, we see that most LDAP data types have friendly .NET data type equivalents, with the vast majority being represented as normal .NET System.String and many of the others as things like DateTime, Int32, and Boolean. However, the table does contain a few strange things, most notably the System.__ComObject, which the experienced .NET programmer may recognize as not even being a public type! We also see that DirectoryEntry and DirectorySearcher marshal some of the types differently.
Figure 6.1 shows a typical layer diagram that illustrates the different places in the native code stack where the various .NET classes get their data.
Figure 6.1. Directory Services API Layers and Data Type Marshaling
Understanding the unusual cases is essential to being fully effective in working with Active Directory and ADAM in .NET. We will delve into the finer points in the next few sections. We will also talk more about the LDAP schema in Chapter 7.
Part I: Fundamentals
Introduction to LDAP and Active Directory
Introduction to .NET Directory Services Programming
Binding and CRUD Operations with DirectoryEntry
Searching with the DirectorySearcher
Advanced LDAP Searches
Reading and Writing LDAP Attributes
Active Directory and ADAM Schema
Security in Directory Services Programming
Introduction to the ActiveDirectory Namespace
Part II: Practical Applications
Part III: Appendixes
Appendix A. Three Approaches to COM Interop with ADSI
Appendix B. LDAP Tools for Programmers
Appendix C. Troubleshooting and Help