2011-12-15 3 views
2

Я пытаюсь получить уведомления об изменениях из активного каталога, чтобы я мог обновлять данные в базе данных, если что-то меняется в моем AD. Я искал и нашел good example от Ryan Dunn.Реализация уведомлений об изменении Active Directory в .NET

Я попытался реализовать его код. Приложение запускается без каких-либо ошибок, но оно не генерирует никаких уведомлений. Кто-нибудь может мне помочь?

Мой домен corp.am2k8vm.com на машине win win 2008 и у меня мало пользователей в активном каталоге для целей тестирования.

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<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(); 
      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<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;} 
    } 
} 
+0

Первое, что нужно учитывать, это безопасность. У вас есть соответствующая безопасность для получения уведомлений. Следующее, что нужно учитывать, - это войти в AD - подумайте об этом и на сервере. Я ничего не знаю об этом в AD, но я начинаю. –

+0

Да, у меня есть привилегии администратора. – user1100889

ответ

4

Я собираюсь заставить вас рассмотреть другой путь в целом, хотя я ничего не знаю о вашем приложении.

Изменение уведомлений все хорошо и хорошо, но есть некоторые недостатки. AD не масштабируется до огромного числа из них. Если вы в автономном режиме, вы пропустите некоторые изменения. И т. Д.

Существует еще один механизм, который я бы рекомендовал вам рассмотреть названный DirSync. Подумайте о DirSync как о «разоблачении» внутреннего протокола репликации AD, предоставленного вам через LDAP. Идея DirSync заключается в том, что вы можете отправить запрос и сказать «что изменилось?». и AD ответят. В ответ - непрозрачный файл cookie. Когда вы снова выпустите запрос в следующий раз, вы снова предоставите файл cookie, и он расскажет вам, что изменилось с момента выпуска последнего файла cookie.

Много хороших элементов этого:

  • DirSync имеет хороший масштаб историю. Вы можете запросить изменения в 1 объект или 1 миллион, и мы знаем, что DirSync будет масштабироваться в соответствии с вашими потребностями.
  • У DirSync есть чистая история для того, чтобы быть в автономном режиме в течение определенного периода времени. Вы можете отключиться на секунду или неделю, вернуться и догнать все, что вы пропустили.
  • Запросы DirSync очень быстрые. Выдавать один раз в минуту или что-то подобное должно быть в порядке.
  • DirSync имеет чистую историю с несколькими DC. Вы можете использовать файл cookie через DC, и он будет (в основном) работать только для вас. (Я говорю в основном, так как вы можете получить дубликаты, но это все).
  • Возможно, больше всего, DirSync имеет очень чистую историю согласованности. Я запускаю клиентов, которые используют DirSync для выполнения эффективного DirSync-запроса в большинстве вызовов, но время от времени (ежедневно? Еженедельно? В месяц? Зависит от приложения ...) вы можете просто выбросить файл cookie и выполнить полную синхронизацию. Это, по сути, заставляет вас действительно разрабатывать чистое решение e2e, которое всегда гарантирует, что у вас будет хороший безопасный способ заставить ваш автономный db согласовываться с истиной в AD, а также быть эффективным на 99% + времени. И «о, что-то пошло не так», путь кода супер хорошо протестирован, так как это путь кода магистрали! И это происходит так же, как и обычный путь кода.

Вам понадобится защитный код, предполагающий, что вы получите дубликаты, но это разумное предположение для большинства приложений.

Надеюсь, это поможет.