Using VS - DevSource
DevSource: Microsoft Developer Resource DevSource Home Sponsored by Microsoft Home Add Ons Architecture Languages Techniques Using VS Forums
Home arrow Using VS arrow Page 4 - Making Sense of ADAM
Making Sense of ADAM
By Shawn Wildermuth

Rate This Article: Add This Article To:

Making Sense of ADAM - ' Accessing ADAM from '
( Page 4 of 4 )

.NET">

Accessing ADAM from .NET

ADAM does not have any special managed code to deal with accessing its data. Because ADAM supports LDAP v3, the DirectoryServices assembly allows access to the ADAM instance. As a result, in this section I'll show you how to access ADAM through DirectoryServices. I assume that you are not familiar with DirectoryServices, for the purpose of this section.

ADVERTISEMENT

Reading Data with the DirectoryEntry Class

You use DirectoryServices' DirectoryEntry class to access objects in ADAM directly. A single DirectoryEntry object represents one ADAM object somewhere in the ADAM hierarchy. The first DirectoryEntry object you open is the gateway to all objects that are connected to that DirectoryEntry. For example, to open the top node in our application instance:

// Open the Top Node of our Instance
DirectoryEntry entry = new DirectoryEntry("LDAP://localhost:20389/cn=MSDN");

// Dump the cn property to the Console
Console.WriteLine(entry.Properties["cn"]);

This code creates a new DirectoryEntry that points to the cn=MSDN node of our ADAM instance. DirectoryEntry lazily loaded, so there is no method to open this object. Upon the first access of some data about the object, it attempts to attach to the path we set. So, when we call the entry.Properties call, the path is validated and the object is set.

To support the hierarchy of objects, the DirectoryEntry class supports a property called Children which contains a collection of all the DirectoryEntry objects directly below itself in the hierarchy. To show this, let's get that same top node again, and show all of the nodes in a TreeView:

void Form1_Load(object sender, EventArgs e)
{
  // Open the Top Node of our Instance
  DirectoryEntry entry = new DirectoryEntry("LDAP://localhost:20389/cn=MSDN");

  // Add the entry to the top of the tree
  TreeNode node = treeView1.Nodes.Add(entry.Name);

  // Add the DirectoryEntry to the tag
  node.Tag = entry;
  
  // Add all the subnodes
  AddEntries(entry, node);
  
}

void AddEntries(DirectoryEntry entry, TreeNode node)
{
  // Go through all children of the entry
  foreach (DirectoryEntry subentry in entry.Children)
  {
    // Add the new subnodes to the TreeView
    TreeNode subnode = node.Nodes.Add(subentry.Name);
    
    // Add the DirectoryEntry to the tag of the node
    subnode.Tag = subentry;

    // Recursively Call this method
    AddEntries(subentry, subnode);
  }
}

In the form's Load event handler, I open the top node and add it to the top of the tree view. I call a new method, called AddEntries, whose job it is to add all the nodes in one level of the tree. It also calls itself recursively to add all the tree's nodes. Using the Children property is the most obvious way to walk the tree of objects.

We have the ADAM objects now, but those objects are just containers for properties. To get at the meat of the objects, we should read some properties:

// Get the value
object value = entry.Properties["cn"].Value;

string valString = ";

All of the specific properties of a particular DirectoryEntry are stored in the Properties. To access a particular property, simply specify its name in the Properties' indexer. The return type is always an object. You can interrogate it at runtime to determine the underlying data type:

// If it is not valid, show "No Value"
if (value == null)
{
  valString = "{No Value}";
}
else if (value is object[])
{
  // If it is multi-valued, try to convert to a string
  foreach (object o in (object[])value)
  {
    valString = string.Format("{0}{1};", valString, o);
  }
}
else
{
  valString = Convert.ToString(value);
}

You can use this little piece of code to attempt to convert whatever is in the value to a string. The value may be null, an array of objects, or a specific object. If the value is null, the value is not set. If the value is an array of objects, then the property is multi-valued and will contain a list of properties. Multi-valued properties are not expected to be returned in a specific order, so do not depend on order of the array. If the value is an object, it is an atomic property value.

The natural next step is to attempt to add new objects or change properties, but before we do that we have to discuss a bit about security and ADAM.

Securely Accessing ADAM

We opened up a DirectoryEntry earlier in this section, like so:

// Open the Top Node of our Instance
DirectoryEntry entry = new DirectoryEntry("LDAP://localhost:20389/cn=MSDN");

Because we have not supplied any security information, we are unlikely to be able to change any ADAM objects. This is so because most of your use with ADAM for is to read data. If that is the case, ADAM is usually open to querying for data to unsecured or anonymous requesters.

In your code, you will likely want to open up DirectoryEntrys in a secure fashion so you can make changes. Some of the options that DirectoryServices gives us for doing this speak to its ability to contact any LDAP v3 data store, so I will not bother iterating the different secure ways of accessing it. For ADAM, the typical way of securing accessing the data store is like so:

// Open the Top Node of our Instance
DirectoryEntry entry = new DirectoryEntry("LDAP://localhost:20389/cn=MSDN",
                                          "username", 
                                          "password", 
                                          AuthenticationTypes.Secure);

In this example, we open up the data store with the same LDAP path, but we supply username, password, and an authentication type. For ADAM, you would typically use the Secure authentication type. The username is a local or domain user. If it is a domain user, you may need to prepend the username with the domain name (e.g. mydomain\myusername). Once you use this secure method, you can change data in the ADAM data store.

Writing Data with the DirectoryEntry Class

In ADAM, all objects are in a large hierarchy. This is important: every object that you create must have some parent. So, the first step in creating a new object in ADAM is securely opening up the parent of that object:

// Open the Top Node of our Instance
DirectoryEntry parent = new DirectoryEntry("LDAP://localhost:20389/cn=MSDN",
                                          "username", 
                                          "password", 
                                          AuthenticationTypes.Secure);

Once we have this object, we can create a new object by simply adding a new object to the Children property:

DirectoryEntry entry = parent.Children.Add("cn=MyNewContainer",
                            "container");

When adding this object, we must specify an LDAP name (e.g. cn=MyNewContainer) for the new object and an objectClass (container, user, etc.).

The new object is created, but we are not done yet. The new object does not yet exist in the ADAM data store. First thing: set any required properties. In this case, the container class only requires the cn property to be set (like all other objectClasses in ADAM). We set this property like so:

// Set the cn (required on all objects)

entry.Properties["cn"].Value = "MyNewContainer";

This may seem duplicative, but it is required. The reasoning behind this has a long history in how LDAP works that I won't bore you with. Please just do it. Trust me.

But we are still not done. We need to save the changes:

// Save the changes
entry.CommitChanges();

The new object does not exist until this is called. Failing to call this causes the object to never be saved. Waiting for Garbage Collection to do the saving does not accomplish anything.

At this point, you know how to add a new object and set properties. What about deleting objects? Because ADAM is a hierarchy, you do not delete an object on its own. When you delete an object, you are actually deleting that object and all of its children (and its children's children). The DirectoryEntry class' DeleteTree method accomplishes deletion for us:

// Delete this object an all below it
entry.DeleteTree();

// Deletion happens immediately, no committing is 
// necessary
//entry.CommitChanges();

You do not need to call the CommitChanges method, since deletion happens immediately.

A Quick Discussion of Performance

Under the covers, DirectoryServices uses the old ADSI COM component. This is good because if you need to do any black magic with ADAM that is not supported by DirectoryServices, you can always get to the underlying ADSI object (DirectoryEntry.NativeObject property). While this is useful, there are COM objects being used under the covers, so you must take extra care to clean up after yourself. If you wait for Garbage Collection, the memory will be freed, but memory will blossom early on. Any DirectoryServices class that contains a reference to a COM object implements the IDisposable interface. As a result, you should Dispose() any object when you are done with it. The pattern is:

// Open the Top Node of our Instance
using (DirectoryEntry entry = 
       new DirectoryEntry("LDAP://localhost:20389/cn=MSDN"))
{

  // Dump the cn property to the Console
  Console.WriteLine(entry.Properties["cn"]);
}

By using the Dispose method, your memory is disposed of in a timely manner. Failing to do this results in huge memory balloons, some of which could bring any machine to its knees. It is fairly simple to do a recursive walk through a tree of some size and consume all available RAM in no time at all.

Conclusion

By this point you should have a good handle on what ADAM is and how it can help in your own applications. Whether you use it as a personalization store for your new Web site or a catalog of products, ADAM can provide you with a performant and robust data store for non-volatile data. By adding ADAM to your data toolbox, you should be able to find the right solution for all your development tasks.



 
 
>>> More Using VS Articles          >>> More By Shawn Wildermuth
 



Microsoft's Future: A Chat With Their CTO, Barry Briggs

Play Video >

All Videos >

Julia explores the Robotics Studio!

Read now >

Messages to Bill Gates!

Read now >

View Now
DevSource RSS FEEDS
XML Want an easy way to keep up with breaking tech news? And the Get DevSource headlines delivered to your desktop with RSS.