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

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

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

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

Я просмотрел stackoverflow и другие источники без везения.

Спасибо.


person Sam    schedule 04.01.2010    source источник


Ответы (1)


Я не уверен, что он делает то, что вам нужно, но взгляните на http://dunnry.com/blog/ImplementingChangeNotificationsInNET.aspx

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



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

  1. Polling for Changes using uSNChanged. This technique checks the 'highestCommittedUSN' value to start and then performs searches for 'uSNChanged' values that are higher subsequently.  The 'uSNChanged' attribute is not replicated between domain controllers, so you must go back to the same domain controller each time for consistency.  Essentially, you perform a search looking for the highest 'uSNChanged' value + 1 and then read in the results tracking them in any way you wish.
    • Benefits
      • This is the most compatible way.  All languages and all versions of .NET support this way since it is a simple search.
    • Disadvantages
      • There is a lot here for the developer to take care of.  You get the entire object back, and you must determine what has changed on the object (and if you care about that change).
      • Работа с удаленными объектами — это боль.
      • Это метод опроса, поэтому в режиме реального времени он зависит от того, как часто вы делаете запросы. Это может быть хорошо в зависимости от приложения. Обратите внимание, здесь также не отслеживаются промежуточные значения.
  2. Polling for Changes Using the DirSync Control.  This technique uses the ADS_SEARCHPREF_DIRSYNC option in ADSI and the LDAP_SERVER_DIRSYNC_OID control under the covers.  Simply make an initial search, store the cookie, and then later search again and send the cookie.  It will return only the objects that have changed.
    • Benefits
      • This is an easy model to follow.  Both System.DirectoryServices and System.DirectoryServices.Protocols support this option.
      • Фильтрация может уменьшить то, с чем вам нужно возиться. Например, если мой первоначальный поиск предназначен для всех пользователей "(objectClass=user)", я могу впоследствии отфильтровать опрос с помощью "(sn=dunn)" и получить только комбинацию обоих фильтров, вместо того, чтобы иметь дело с все из начального фильтра.
      • Параметр Windows 2003+ снимает административное ограничение на использование этого параметра (безопасность объекта).
      • Опция Windows 2003+ также даст вам возможность возвращать только добавочные значения, которые изменились в больших многозначных атрибутах. Это действительно хорошая функция.
      • Хорошо справляется с удаленными объектами.
    • Disadvantages
      • This is .NET 2.0+ or later only option.  Users of .NET 1.1 will need to use uSNChanged Tracking.  Scripting languages cannot use this method.
      • Вы можете ограничить поиск только разделом. Если вы хотите отслеживать только конкретную OU или объект, вы должны самостоятельно отсортировать эти результаты позже.
      • Использование этого с доменами режима, отличного от Windows 2003, связано с ограничением, которое заключается в том, что вы должны иметь разрешения на получение изменений репликации (по умолчанию только администратор).
      • Это метод опроса. Он также не отслеживает промежуточные значения. Таким образом, если объект, который вы хотите отслеживать, изменяется между поисками несколько раз, вы получите только последнее изменение. Это может быть преимуществом в зависимости от приложения.
  3. Change Notifications in Active Directory.  This technique registers a search on a separate thread that will receive notifications when any object changes that matches the filter.  You can register up to 5 notifications per async connection.
    • Benefits
      • Instant notification.  The other techniques require polling.
      • Поскольку это уведомление, вы получите все изменения, даже промежуточные, которые были бы потеряны в двух других методах.
    • Disadvantages
      • Relatively resource intensive.  You don't want to do a whole ton of these as it could cause scalability issues with your controller.
      • Это только говорит вам, изменился ли объект, но не говорит вам, что это было за изменение. Вам нужно выяснить, изменился ли интересующий вас атрибут или нет. При этом довольно легко определить, был ли удален объект (по крайней мере, проще, чем опрос uSNChanged).
      • Это можно сделать только в неуправляемом коде или с помощью System.DirectoryServices.Protocols.

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

Моя первая мысль при написании этого состояла в том, чтобы использовать .com%2fen-us%2flibrary%2fms676877.aspx" rel="noreferrer">пример кода, найденный в 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();
}
person stuartd    schedule 04.01.2010
comment
@stuartd Итак, у меня это работает, RXing уведомления об изменениях и все такое. Но я получаю около 30 атрибутов, ни один из которых не отличается от их текущей конфигурации. Я пропустил часть, где мы можем получить только измененные предметы? - person Wjdavis5; 18.07.2014
comment
@ Wjdavis5, ты должен задать новый вопрос. - person stuartd; 18.07.2014
comment
Это решение работает, если мне нужно перехватывать только сообщения аутентификации? - person Marco; 11.03.2018
comment
@ Марко через восемь лет после того, как я это опубликовал? Я понятия не имею. Почему бы тебе не попробовать, - person stuartd; 12.03.2018
comment
@stuartd Привет. Он говорит, что CreateConnection не был найден в данном контексте. Какова реализация CreateConnection? - person Macindows; 21.05.2020
comment
@Macindows исходная статья все еще доступна, и если я что-то пропустил, это будет там. - person stuartd; 21.05.2020
comment
Можем ли мы получить уведомление, когда изменяется только определенное свойство из AD? Например, отслеживать только роль из AD, и AD должна уведомлять меня только при изменении роли любого сотрудника? - person Vishal; 21.10.2020