Регистрация уведомления об изменении с помощью Active Directory с использованием C#

StackOverflow https://stackoverflow.com/questions/2002606

Вопрос

Эта ссылка http://msdn.microsoft.com/en-us/library/aa772153(vs.85).aspx говорит:

Вы можете зарегистрировать до пяти запросов уведомлений на одном соединении LDAP. У вас должна быть выделенная нить, которая ждет уведомлений и быстро их обрабатывает. Когда вы вызовите функцию LDAP_SEARCH_EXT, чтобы зарегистрировать запрос уведомления, функция возвращает идентификатор сообщения, который идентифицирует этот запрос. Затем вы используете функцию LDAP_RESULT, чтобы ждать уведомлений об изменениях. Когда происходит изменение, сервер отправляет вам сообщение LDAP, которое содержит идентификатор сообщения для запроса уведомления, который сгенерировал уведомление. Это приводит к возвращению функции LDAP_RESULT с результатами поиска, которые идентифицируют измененный объект.

Я не могу найти подобное поведение, просматривая документацию .NET. Если бы кто -нибудь знал, как это сделать в C#, я был бы очень рад знать. Я ищу, когда атрибуты изменяются на всех пользователей в системе, чтобы я мог выполнять пользовательские действия в зависимости от того, что изменилось.

Я не повезло через Stackoverflow и другие источники.

Спасибо.

Это было полезно?

Решение

Я не уверен, что он делает то, что вам нужно, но посмотрите на http://dunnry.com/blog/implementingchangenotificationsinnet.aspx

Изменить: добавлен текст и код из статьи:



Есть три способа выяснения вещей, которые изменились в Active Directory (или ADAM). Они были задокументированы в течение некоторого времени в MSDN в точно названном "Обзор методов отслеживания изменений »Анкет В итоге:

  1. Опрос для изменений с использованием usnchanged. Анкет Этот метод проверяет значение «Наиболее изначальное количество», чтобы запустить, а затем выполняет поиск значений «usnchanged», которые впоследствии выше. Атрибут «usnchanged» не реплицируется между контроллерами домена, поэтому вы должны возвращаться к одному и тому же контроллеру домена каждый раз для согласованности. По сути, вы выполняете поиск в поисках самого высокого «usnchanged» значения + 1, а затем читаете в результатах, отслеживая их любым способом.
    • Преимущества
      • Это самый совместимый способ. Все языки и все версии .NET поддерживают таким образом, так как это простой поиск.
    • Недостатки
      • Здесь есть много для разработчика, о котором нужно позаботиться. Вы верните весь объект, и вы должны определить, что изменилось на объекте (и если вы заботитесь об этом изменении).
      • Работа с удаленными объектами - это боль.
      • Это техника опроса, так что это только в реальном времени, как часто вы запрашиваете. Это может быть хорошей вещью в зависимости от приложения. Примечание, промежуточные значения здесь тоже не отслеживаются.
  2. Опрос для изменений с использованием контроля DirsyncАнкет В этом методе используется опция ADS_SearchPref_dirsync в ADSI и управление LDAP_SERVER_DIRSYNC_OID под обложками. Просто сделайте первоначальный поиск, храните файл cookie, а затем снова найдите и отправьте cookie. Это вернет только те объекты, которые изменились.
    • Преимущества
      • Это простая модель, чтобы следовать. Как System.DirectoryServices, так и System.DirectoryServices.Protocols поддерживают эту опцию.
      • Фильтрация может уменьшить то, с чем вам нужно беспокоиться. В качестве примера, если мой первоначальный поиск предназначен для всех пользователей "(ObjectClass = пользователь)", я впоследствии могу фильтровать на опросе "(sn = dunn)" и только вернуть комбинацию обоих фильтров, вместо того, чтобы иметь дело с Все от интенсивного фильтра.
      • Опция Windows 2003+ Удаляет административное ограничение для использования этой опции (безопасность объекта).
      • Опция Windows 2003+ также даст вам возможность вернуть только дополнительные значения, которые изменились в больших многозначных атрибутах. Это действительно хорошая особенность.
      • Хорошо справляется с удаленными объектами.
    • Недостатки
      • Это вариант .NET 2.0+ или более позднее. Пользователи .NET 1.1 должны будут использовать отслеживание USNCHANGED. Языки сценариев не могут использовать этот метод.
      • Вы можете только охватить поиск в раздел. Если вы хотите отслеживать только конкретный OU или объект, вы должны разобраться в этих результатах сами позже.
      • Использование этого с доменами режима Non-Windows 2003 поставляется с ограничением, которое вы должны иметь репликацию получить разрешения (только администратор по умолчанию) для использования.
      • Это техника опроса. Он также не отслеживает промежуточные значения. Итак, если объект, который вы хотите отслеживать изменения между поисками несколько раз, вы получите только последнее изменение. Это может быть преимуществом в зависимости от приложения.
  3. Изменения уведомлений в Active DirectoryАнкет Этот метод регистрирует поиск в отдельном потоке, который будет получать уведомления при изменении любого объекта, который соответствует фильтру. Вы можете зарегистрировать до 5 уведомлений на асинхронное соединение.
    • Преимущества
      • Мгновенное уведомление. Другие методы требуют опроса.
      • Поскольку это уведомление, вы получите все изменения, даже промежуточные, которые были бы потеряны в двух других методах.
    • Недостатки
      • Относительно ресурсный интенсивный. Вы не хотите делать целую тонну, так как это может вызвать проблемы с масштабируемостью с вашим контроллером.
      • Это только говорит вам, что объект изменился, но он не говорит вам, что это за изменение. Вам нужно выяснить, изменился ли вам атрибут, который вы заботитесь, или нет. При этом, довольно легко сказать, был ли объект удален (проще, чем USNCHANGED OR OPRICLICE, по крайней мере).
      • Вы можете сделать это только в неуправляемом коде или с System.DirectoryServices.Protocols.

По большей части я обнаружил, что Dirsync соответствует мне практически в любой ситуации. Я никогда не удосужился попробовать другие методы. Тем не менее, читатель спросил, есть ли способ сделать уведомления об изменениях в .net. Я подумал, что это возможно с использованием SDS.P, но никогда не пробовал. Оказывается, это возможно и на самом деле не слишком сложно сделать.

Моя первая мысль о написании этого состояла в том, чтобы использовать образец кода найден на MSDN (и ссылаются из опции № 3) и просто преобразуйте это в System.DirectoryServices.protocols. Это оказалось тупиком. То, как вы делаете это в SDS.P, и то, как работает пример кода, достаточно отличается, чтобы он не помог. Вот решение, которое я придумал:

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;}
}

Это относительно простой класс, который вы можете использовать для регистрации поиска. Хитрость заключается в использовании метода GetPartialResults в методе обратного вызова, чтобы получить только только что произошло изменение. Я также включил очень упрощенный класс EventArgs, который я использую для передачи результатов. Обратите внимание, что я ничего не делаю с потоками здесь, и у меня нет обработки ошибок (это просто образец). Вы можете употреблять этот класс так:

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();
    Console.WriteLine("====================");
    Console.WriteLine();
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top