A Tale of Two LDAP Stacks
As you may or may not know, .NET contains two completely different ways to program LDAP. Version 1.x contained the System.DirectoryServices (SDS) namespace, which is a managed wrapper around ADSI and supports LDAP programming via the LDAP ADSI provider. This is what most people tend to think of when then think of LDAP programming in .NET. 2.0 adds a bunch of new features, but is generally speaking the exact same thing for S.DS.
However, .NET 2.0 also contains something new and entirely different called System.DirectoryServices.Protocols (SDS.P). Instead of using ADSI, SDS.P interops directly with Microsoft's LDAP API (implemented in wldap32.dll), which is a lower level mechanism for doing LDAP that provides complete control over all of the features exposed by the LDAP in general, including some things that are simply not possible with ADSI (either due to the the design of ADSI or the fact that they things are obscure enough to have never been wrapped). Another interesting aspect of SDS.P is that it also supports the Directory Services Markup Language (DSML) protocol, which basically let's you talk LDAP using SOAP over HTTP. Microsoft actually ships a DSML server for AD and ADAM, but it is surprisingly unpopular, especially given all the focus on SOAP these days. One of the big problems for adoption with DSML in the past was that you had to do all the SOAP stuff in raw XML as there was no WSDL to generate friendly proxies, so maybe having an easy to program API will change that? I've never used it. :) Anyway, DSML and "normal" TCP/IP LDAP are actually implemented using a provider model, which makes the object model pretty easy to consume for both. Most of it is identical except for the initial connection setup.
It Used to Be So Simple...
So, which to use? In the past, there was a great natural disparity between pure LDAP programming and ADSI programming, as LDAP only supported C or C++ language bindings, while ADSI was designed from the go for scripting and OLE automation and was vastly easier to consume. Even if you really needed some of the features you could only get with pure LDAP, the C compiler requirement tended to price most people right out of the skill set needed to accomplish such things.
However, that's really no longer true in .NET 2.0. While it is definitely the case that SDS.P is generally more complicated to do the same stuff and will often take 2x as much code, the difference between the two is actually much smaller. For example, I can now program SDS and SDS.P in VB.NET and can actually mix the two in the same program if I'm so inclined. The gap is much narrower.
When Ryan and I first started working on the book, .NET 2.0 was still out on the horizon and we hadn't really seen much SDS.P yet. We came from a background of having built some nasty stuff using SDS and felt like we had some really deeply useful information to share there. However, as the writing took us longer and longer and .NET 2.0 got closer and closer, we realized that a) we really needed to cover .NET 2.0, and b) that SDS.P was a part of the story that we needed to figure out a way to tell.
The approach we took in the book to deal with this was a little mixed in my opinion. We really didn't cover much SDS.P at all. To the extent that we taught a lot of the fundamentals of programming AD and ADAM that could apply to any protocol, I think we were successful in providing a lot of information that could have been easily translated to SDS.P. However, we didn't really take the approach of building up the basics like we did with SDS. Instead, we basically just dove into SDS.P when we ran out of room in SDS, leaving some of our SDS.P examples as fairly hairy (the async one comes to mind here, especially as the first code sample to use SDS.P!). Of course, if we had done the opposite, the book would have been much longer and we might have never finished, so there is that...
The other thing is that Ryan and I are both nerds and SDS.P is kind of like a new toy, so we are both now tempted to use it for everything, even if it takes twice as long, just because it is interesting. However, that doesn't make any practical sense, especially when someone else is paying for your time and may have less skilled developers inheriting your stuff! So, when to use SDS.P? I'll submit my humble list and then try to show some examples of some of this stuff over the next few weeks:
When You Really DO Need SDS.P
- You really do need to do DSML (maybe I'll meet one of you someday :))
- Digest authentication against ADAM
- Explicit control over client or server certificate handling with SSL/LDAP
- Phantom root queries
- Fast concurrent binding in AD 2003 and ADAM (not the same as the FastBind flag in SDS!)
- Access to the LDAP Compare operation
- Working with LDAP V2 directories that support a custom schema (nothing MS ships...)
- Applications where explicit control over the LDAP connection is important for scalability, such as programmatic LDAP authentication, or web applications that use Kerberos delegation to acces the directory and support many many different simultaneous users (ADSI really fights you here)
- Applications where the ADSI schema mapping mechanism is more of a problem than a boon
- Server apps where there can be a real scalability benefit to using the full asynch capabilities of SDS.P
- Needing to change credentials when chasing a referral (a nasty situation, but sometimes this happens)
There will also always be people who come from an LDAP or JNDI background, for whom SDS.P will probably feel more comfortable. Additionally, if one were building a fully abstracted DAL over an LDAP store, the incremental difference in using SDS.P might not be so much, especially if you invested up front in some code gen. But otherwise, SDS is probably still the sweet spot for most of us.
In my next post on this topic, I'll show how you can do something with SDS.P and SSL that you simply cannot do in SDS--get the expiration date of each certificate on each DC in your forest! If you use external certificates and need to renew by hand, this is pretty handy.