Я не уверен, что он делает то, что вам нужно, но взгляните на http://dunnry.com/blog/ImplementingChangeNotificationsInNET.aspx
Изменить: добавлен текст и код из статьи:
Есть три способа выяснить, что изменилось в Active Directory (или ADAM). Они были задокументированы в течение некоторого времени в MSDN в метком названии "Обзор методов отслеживания изменений". В итоге:
- 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).
- Работа с удаленными объектами — это боль.
- Это метод опроса, поэтому в режиме реального времени он зависит от того, как часто вы делаете запросы. Это может быть хорошо в зависимости от приложения. Обратите внимание, здесь также не отслеживаются промежуточные значения.
- 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, связано с ограничением, которое заключается в том, что вы должны иметь разрешения на получение изменений репликации (по умолчанию только администратор).
- Это метод опроса. Он также не отслеживает промежуточные значения. Таким образом, если объект, который вы хотите отслеживать, изменяется между поисками несколько раз, вы получите только последнее изменение. Это может быть преимуществом в зависимости от приложения.
- 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