title: Implementing Active Directory Change Notifications in .NET
body: <p>I am trying to get change notifications from active directory, so that I can update data in database if anythinghanges in my AD. I searched and found a <a href="http://dunnry.com/blog/ImplementingChangeNotificationsInNET.aspx" rel="nofollow">good example</a> by Ryan Dunn.</p>
  
  <p>I tried implementing his code. The application starts without any errors but it is not generating me any notification. Can someone help me out?</p>
  
  <p>My domain is <code>corp.am2k8vm.com</code> on win 2008 server machine and i have few users on active directory for testing purposes. </p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.DirectoryServices.Protocols;
  using System.DirectoryServices;
  namespace ChangeNotifications
  {
      class Program
      {
          static void Main(string[] args)
          {
              using (LdapConnection connect = CreateConnection("192.168.182.209"))                //can also use localhost
              {
                  using (ChangeNotifier notifier = new ChangeNotifier(connect))
                  {
                      //register some objects for notifications (limit 5)
                      notifier.Register("dc=am2k8vm,dc=com", SearchScope.OneLevel);                     //not sure if the parameters are correct here as i am new to active directory stuff
                      notifier.Register("cn=Andy Main,ou=users,dc=am2k8vm,dc=com", SearchScope.Base); //not sure if the parameters are correct here as i am new to active directory stuff
                      notifier.ObjectChanged += new EventHandler&lt;ObjectChangedEventArgs&gt;(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();
              Console.WriteLine("====================");
              Console.WriteLine();
          }
          static private LdapConnection CreateConnection(string server)
          {
              LdapConnection connect = new LdapConnection(server);
              connect.SessionOptions.ProtocolVersion = 3;
              connect.AuthType = AuthType.Negotiate;  //use my current credentials
              return connect;
          }
      }
      public class ChangeNotifier : IDisposable
      {
          LdapConnection _connection;
          HashSet&lt;IAsyncResult&gt; _results = new HashSet&lt;IAsyncResult&gt;();
  
          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&lt;ObjectChangedEventArgs&gt; 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;}
      }
  }
  </code></pre>