There are three ways of figuring out things that have changed in Active Directory (or ADAM). These have been documented for some time over at MSDN in the aptly titled "Overview of Change Tracking Techniques". In summary:
For the most part, I have found that DirSync has fit the bill for me in virtually every situation. I never bothered to try any of the other techniques. However, a reader asked if there was a way to do the change notifications in .NET. I figured it was possible using SDS.P, but had never tried it. Turns out, it is possible and actually not too hard to do.
My first thought on writing this was to use the sample code found on MSDN (and referenced from option #3) and simply convert this to System.DirectoryServices.Protocols. This turned out to be a dead end. The way you do it in SDS.P and the way the sample code works are different enough that it is of no help. Here is the solution I came up with:
public class ChangeNotifier : IDisposable
{
LdapConnection _connection;
HashSet<IAsyncResult> _results = new HashSet<IAsyncResult>();
public ChangeNotifier(LdapConnection connection)
_connection = connection;
_connection.AutoBind = true;
}
public void Register(string dn, SearchScope scope)
SearchRequest request = new SearchRequest(
dn, //root the search here
"(objectClass=*)", //very inclusive
scope, //any scope works
null //we are interested in all attributes
);
//register our search
request.Controls.Add(new DirectoryNotificationControl());
//we will send this async and register our callback
//note how we would like to have partial results
IAsyncResult result = _connection.BeginSendRequest(
request,
TimeSpan.FromDays(1), //set timeout to a day...
PartialResultProcessing.ReturnPartialResultsAndNotifyCallback,
Notify,
request
//store the hash for disposal later
_results.Add(result);
private void Notify(IAsyncResult result)
//since our search is long running, we don't want to use EndSendRequest
PartialResultsCollection prc = _connection.GetPartialResults(result);
foreach (SearchResultEntry entry in prc)
OnObjectChanged(new ObjectChangedEventArgs(entry));
private void OnObjectChanged(ObjectChangedEventArgs args)
if (ObjectChanged != null)
ObjectChanged(this, args);
public event EventHandler<ObjectChangedEventArgs> ObjectChanged;
#region IDisposable Members
public void Dispose()
foreach (var result in _results)
//end each async search
_connection.Abort(result);
#endregion
public class ObjectChangedEventArgs : EventArgs
public ObjectChangedEventArgs(SearchResultEntry entry)
Result = entry;
public SearchResultEntry Result { get; set;}
It is a relatively simple class that you can use to register searches. The trick is using the GetPartialResults method in the callback method to get only the change that has just occurred. I have also included the very simplified EventArgs class I am using to pass results back. Note, I am not doing anything about threading here and I don't have any error handling (this is just a sample). You can consume this class like so:
static void Main(string[] args)
using (LdapConnection connect = CreateConnection("localhost"))
using (ChangeNotifier notifier = new ChangeNotifier(connect))
//register some objects for notifications (limit 5)
notifier.Register("dc=dunnry,dc=net", SearchScope.OneLevel);
notifier.Register("cn=testuser1,ou=users,dc=dunnry,dc=net", SearchScope.Base);
notifier.ObjectChanged += new EventHandler<ObjectChangedEventArgs>(notifier_ObjectChanged);
Console.WriteLine("Waiting for changes...");
Console.WriteLine();
Console.ReadLine();
static void notifier_ObjectChanged(object sender, ObjectChangedEventArgs e)
Console.WriteLine(e.Result.DistinguishedName);
foreach (string attrib in e.Result.Attributes.AttributeNames)
foreach (var item in e.Result.Attributes[attrib].GetValues(typeof(string)))
Console.WriteLine("\t{0}: {1}", attrib, item);
Console.WriteLine("====================");
And there you have it... change notifications in .NET. You can also download my project file for Visual Studio 2008.
Comments [0] October 30, 2007
This is the personal site of Ryan Dunn, co-author of the The .NET Developers Guide to Directory Services Programming.
Ryan currently works for Microsoft and is the Technical Evangelist for Windows Azure
Buy the Book
Contact Ryan