在 .NET 中实现 Active Directory 更改通知
我正在尝试从活动目录获取更改通知,以便在我的 AD 中发生任何变化时可以更新数据库中的数据。我搜索并找到了 Ryan Dunn 的很好的示例。
我尝试实现他的代码。应用程序启动时没有任何错误,但它没有向我生成任何通知。有人可以帮我吗?
我的域是 win 2008 服务器计算机上的 corp.am2k8vm.com,并且出于测试目的,我在 Active Directory 上几乎没有用户。
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;}
}
}
I am trying to get change notifications from active directory, so that I can update data in database if anythinghanges in my AD. I searched and found a good example by Ryan Dunn.
I tried implementing his code. The application starts without any errors but it is not generating me any notification. Can someone help me out?
My domain is corp.am2k8vm.com
on win 2008 server machine and i have few users on active directory for testing purposes.
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;}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
尽管我对您的应用程序一无所知,但我将敦促您考虑完全不同的路径。
更改通知固然很好,但也有一些缺点。 AD 无法扩展到大量的数据。如果您离线一段时间,您会错过一些更改。等等。
我鼓励您考虑另一种机制,名为 DirSync。将 DirSync 视为 AD 内部复制协议的“原始暴露”,通过 LDAP 提供给您。 DirSync 的想法是,您可以发出查询并询问“发生了什么变化?” AD 会回答。答案是一个不透明的cookie。当您下次再次发出查询时,您再次提供 cookie,它会告诉您自上次发出 cookie 以来发生了什么变化。
其中有很多不错的元素:
假设您得到了重复更改,您需要进行防御性编码,但这对于大多数应用程序来说是一个合理的假设。
希望这有帮助。
I'm going to push you to consider a different path altogether, even though I know nothing about your app.
Change notifications are all well and good, but there are some downsides. AD doesn't scale to huge numbers of them. If you are offline for a while you miss some changes. Etc.
There is another mechanism I would encourage you to consider named DirSync. Think of DirSync as a "raw expose" of the AD internal replication protocol, given to you over LDAP. The idea of DirSync is that you can issue a query and say "what's changed?" and AD will answer. In with the answer is an opaque cookie. When you issue the query again next time, you provide the cookie again and it will tell you what has changed since the last cookie was issued.
Lots of nice elements of this:
You would need to defensively code assuming you get dup changes, but that's a reasonable assumption for most apps.
Hope this helps.