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

В этой ссылке http://msdn.microsoft.com/en-us/library/aa772153 (По сравнению с 85) .aspx говорится:

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

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

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

Спасибо.

11
задан Per Noalt 5 January 2010 в 05:05
поделиться

1 ответ

[

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

]. [

] Правка: Добавлен текст и код из статьи: [

]. [

][

][
][
] [

] Есть три способа выяснить вещи, которые изменились в Active Directory (или ADAM).  Они были задокументированы в течение некоторого времени в MSDN в уместном названии "[]Overview of Change Tracking Techniques"[].  Вкратце:[

] [
    ] [
  1. ] [] Опрос на предмет изменений с использованием uSNChanged[]. Данный метод проверяет для начала значение 'highCommittedUSN', а затем выполняет поиск значений 'uSNChanged', которые впоследствии будут выше.  Атрибут 'uSNChanged' не реплицируется между контроллерами домена, поэтому необходимо каждый раз возвращаться на один и тот же контроллер домена для последовательности.  По сути, вы выполняете поиск по максимальному значению 'uSNChanged' + 1, а затем читаете результаты, отслеживая их любым удобным вам способом. [
      ] [
    • ] Преимущества [
        ] [
      • ] Это наиболее совместимый способ.  Все языки и все версии .NET поддерживают этот способ, так как это простой поиск. [
      • ] [
      ] [
    • ] [
    • ] Недостатки [
        ] [
      • ] Здесь разработчику есть о чем позаботиться.  Вы получаете весь объект обратно, и вы должны определить, что изменилось на объекте (и если вас волнует это изменение). [
      • ] [
      • ] Работа с удаленными объектами - это боль. [
      • ][
      • ]Это техника опроса, поэтому она работает только в реальном времени, как часто Вы делаете запросы.  Это может быть хорошо в зависимости от приложения. Обратите внимание, здесь также не отслеживаются промежуточные значения. [
      • ][
      ][
    • ][
    ] [
  2. ][
  3. ][]Опрос изменений с помощью DirSync Control[].  Эта техника использует опцию ADS_SEARCHPREF_DIRSYNC в ADSI и управление LDAP_SERVER_DIRSYNC_OID под крышками.  Просто выполните начальный поиск, сохраните файл cookie, а затем снова выполните поиск и отправьте файл cookie.  Он вернет только те объекты, которые изменились. [
      ] [
    • ] Преимущества [
        ] [
      • ] Эта модель проста в использовании.  Как System.DirectoryServices, так и System.DirectoryServices.Protocols поддерживают эту опцию. [
      • ] [
      • ] Фильтрация может уменьшить количество проблем.  Например, если я ищу всех пользователей "(objectClass=user)", я могу впоследствии отфильтровать опрос с помощью "(sn=dunn)" и получить обратно только комбинацию обоих фильтров, вместо того, чтобы иметь дело со всем, что происходит с промежуточным фильтром. [
      • ][
      • ]Опция Windows 2003+ снимает административное ограничение на использование этой опции (защита объекта). Опция [
      • ][
      • ]Windows 2003+ также позволяет возвращать только те инкрементальные значения, которые изменились в больших многозначных атрибутах.  Это действительно хорошая функция. [
      • ][
      • ]Хорошо работает с удаленными объектами. [
      • ] [
      ] [
    • ] [
    • ] Недостатки [
        ] [
      • ] Это только опция .NET 2.0+ или более поздней версии.  Пользователи .NET 1.1 должны будут использовать uSNChanged Tracking.  Языки сценариев не могут использовать этот метод. [
      • ][
      • ]Можно выполнить поиск только по разделу.  Если вы хотите отследить только определенную OU или объект, вы должны разобраться с этими результатами самостоятельно позже. [
      • ][
      • ]Использование этого метода для доменов, не относящихся к режиму Windows 2003, поставляется с ограничением, для использования которого вы должны иметь права на репликацию (по умолчанию используется только администратор). [
      • ][
      • ]Это метод опроса.  Она также не отслеживает промежуточные значения.  Поэтому, если объект, который вы хотите отслеживать изменения между поисками несколько раз, вы получите только последнее изменение.  Это может быть преимуществом в зависимости от приложения. [
      • ][
      ][
    • ][
    ] [
  4. ][
  5. ][] Уведомления об изменениях в Active Directory[].  Данный метод регистрирует поиск в отдельном потоке, который будет получать уведомления при изменении любого объекта, соответствующего фильтру.  На одно асинхронное соединение можно зарегистрировать до 5 уведомлений. Преимущества [
      ] [
    • ] Преимущества [
        ] [
      • ] Мгновенные уведомления.  Другие методы требуют опроса. [
      • ] [
      • ] Поскольку это уведомление, вы получите все изменения, даже промежуточные, которые были бы потеряны в двух других методиках. [
      • ] [
      ] [
    • ] [
    • ] Недостатки [
        ] [
      • ] Относительно ресурсоемкие.  Вы не захотите делать целую тонну этого, так как это может привести к проблемам с масштабируемостью вашего контроллера. [
      • ] [
      • ] Это только скажет Вам, изменился ли объект, но не скажет Вам, что это было за изменение.  Вам нужно выяснить, изменился ли интересующий Вас атрибут или нет.  При этом довольно легко определить, был ли объект удалён (по крайней мере, проще, чем опрос uSNChanged). [
      • ] [
      • ] Это можно сделать только в неуправляемом коде или с помощью System.DirectoryServices.Protocols. [
      • ] [
      ] [
    • ] [
    ] [
  6. ] [
] [

] [

] По большей части я обнаружил, что 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();
}
]
18
ответ дан 3 December 2019 в 06:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: