Реализация уведомлений об изменениях Active Directory в .NET - PullRequest
2 голосов
/ 16 декабря 2011

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

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

Мой домен - corp.am2k8vm.com на компьютере-сервере 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;}
    }
}

1 Ответ

4 голосов
/ 16 декабря 2011

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

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

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

Много приятных элементов этого:

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...