使用 C# 向 Active Directory 注册更改通知

Registering change notification with Active Directory using C#(使用 C# 向 Active Directory 注册更改通知)
本文介绍了使用 C# 向 Active Directory 注册更改通知的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

此链接 http://msdn.microsoft.com/en-us/library/aa772153(VS.85).aspx 说:

您最多可以在单个 LDAP 连接上注册五个通知请求.您必须有一个专用线程来等待通知并快速处理它们.当您调用 ldap_search_ext 函数注册通知请求时,该函数会返回标识该请求的消息标识符.然后使用 ldap_result 函数等待更改通知.发生更改时,服务器会向您发送一条 LDAP 消息,其中包含生成通知的通知请求的消息标识符.这会导致 ldap_result 函数返回标识更改对象的搜索结果.

You can register up to five notification requests on a single LDAP connection. You must have a dedicated thread that waits for the notifications and processes them quickly. When you call the ldap_search_ext function to register a notification request, the function returns a message identifier that identifies that request. You then use the ldap_result function to wait for change notifications. When a change occurs, the server sends you an LDAP message that contains the message identifier for the notification request that generated the notification. This causes the ldap_result function to return with search results that identify the object that changed.

我在 .NET 文档中找不到类似的行为.如果有人知道如何在 C# 中做到这一点,我将不胜感激.我希望查看系统中所有用户的属性何时发生更改,以便我可以根据更改的内容执行自定义操作.

I cannot find a similar behavior looking through the .NET documentation. If anyone knows how to do this in C# I'd be very grateful to know. I'm looking to see when attributes change on all the users in the system so I can perform custom actions depending on what changed.

我浏览了 stackoverflow 和其他来源但没有运气.

I've looked through stackoverflow and other sources with no luck.

谢谢.

推荐答案

我不确定它是否满足您的需求,但请查看 http://dunnry.com/blog/ImplementingChangeNotificationsInNET.aspx

I'm not sure it does what you need, but have a look at http://dunnry.com/blog/ImplementingChangeNotificationsInNET.aspx

从文章中添加文本和代码:

Added text and code from the article:



有三种方法可以确定 Active Directory(或 ADAM)中发生的变化. 这些已经在 MSDN 的适当标题更改跟踪技术概述". 总结:

There are three ways of figuring out things that have changed in Active Directory (or ADAM).  These have been documented for some time over at MSDN in the aptly titled "Overview of Change Tracking Techniques".  In summary:

  1. 使用 uSNChanged 轮询更改.此技术检查highestCommittedUSN"值以启动,然后搜索随后更高的uSNChanged"值. 'uSNChanged' 属性不会在域控制器之间复制,因此您必须每次都返回到同一个域控制器以保持一致性. 本质上,您执行搜索以查找最高的uSNChanged"值 + 1,然后以您希望的任何方式读取跟踪它们的结果.
    • 优点
      • 这是最兼容的方式. 所有语言和 .NET 的所有版本都支持这种方式,因为它是一种简单的搜索.
  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.
  • 这里有很多事情需要开发人员照顾. 您取回整个对象,并且您必须确定对象上发生了什么变化(以及您是否关心该变化).
  • 处理已删除的对象很痛苦.
  • 这是一种轮询技术,因此它的实时性取决于您查询的频率. 这可能是一件好事,具体取决于应用程序.请注意,此处也不跟踪中间值.
  • 优点
    • 这是一个易于遵循的模型. System.DirectoryServices 和 System.DirectoryServices.Protocols 都支持此选项.
    • 过滤可以减少您需要烦恼的事情. 例如,如果我的初始搜索是针对所有用户(objectClass=user)",我随后可以使用(sn=dunn)"对轮询进行过滤,并且只返回两个过滤器的组合,而不必处理来自初始过滤器的一切.
    • Windows 2003+ 选项消除了使用此选项(对象安全)的管理限制.
    • Windows 2003+ 选项还可以让您仅返回在大型多值属性中已更改的增量值. 这是一个非常好的功能.
    • 很好地处理已删除的对象.
    • 这是 .NET 2.0+ 或更高版本的唯一选项. .NET 1.1 的用户将需要使用 uSNChanged 跟踪. 脚本语言不能使用这种方法.
    • 您只能将搜索范围限定到一个分区. 如果您只想跟踪特定的 OU 或对象,您必须稍后自己整理这些结果.
    • 在非 Windows 2003 模式域中使用它会带来限制,即您必须具有复制获取更改权限(默认只有管理员)才能使用.
    • 这是一种轮询技术. 它也不跟踪中间值. 因此,如果您要跟踪多次搜索之间的更改的对象,您将只会获得最后一次更改. 根据应用,这可能是一个优势.
    • 优点
      • 即时通知. 其他技术需要轮询.
      • 因为这是一个通知,所以您将获得所有更改,即使是在其他两种技术中会丢失的中间更改.
      • 资源相对密集. 您不想做很多这样的事情,因为它可能会导致您的控制器出现可扩展性问题.
      • 这只会告诉您对象是否已更改,但不会告诉您更改是什么. 您需要弄清楚您关心的属性是否已更改. 话虽如此,很容易判断对象是否已被删除(至少比 uSNChanged 轮询更容易).
      • 您只能在非托管代码中或使用 System.DirectoryServices.Protocols 执行此操作.

      在大多数情况下,我发现 DirSync 几乎在所有情况下都适合我. 我从来没有费心去尝试任何其他技术. 但是,一位读者询问是否有办法在 .NET 中执行更改通知. 我认为使用 SDS.P 是可能的,但从未尝试过. 事实证明,这是可能的,而且实际上并不难做到.

      For the most part, I have found that DirSync has fit the bill for me in virtually every situation.  I never bothered to try any of the other techniques.  However, a reader asked if there was a way to do the change notifications in .NET.  I figured it was possible using SDS.P, but had never tried it.  Turns out, it is possible and actually not too hard to do.

      我写这篇文章的第一个想法是使用 示例代码MSDN(并从选项 #3 中引用)并将其简单地转换为 System.DirectoryServices.Protocols. 结果证明这是一个死胡同. 您在 SDS.P 中执行此操作的方式和示例代码的工作方式大不相同,以至于没有任何帮助. 这是我想出的解决方案:

      My first thought on writing this was to use the sample code found on MSDN (and referenced from option #3) and simply convert this to System.DirectoryServices.Protocols.  This turned out to be a dead end.  The way you do it in SDS.P and the way the sample code works are different enough that it is of no help.  Here is the solution I came up with:

      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 类,我用来将结果传回.请注意,我在这里没有做任何关于线程的事情,也没有任何错误处理(这只是一个示例).你可以像这样使用这个类:

      It is a relatively simple class that you can use to register searches. The trick is using the GetPartialResults method in the callback method to get only the change that has just occurred. I have also included the very simplified EventArgs class I am using to pass results back. Note, I am not doing anything about threading here and I don't have any error handling (this is just a sample). You can consume this class like so:

      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("	{0}: {1}", attrib, item);
              }
          }
          Console.WriteLine();
          Console.WriteLine("====================");
          Console.WriteLine();
      }
      

      这篇关于使用 C# 向 Active Directory 注册更改通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

      本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

ActiveDirectory error 0x8000500c when traversing properties(遍历属性时 ActiveDirectory 错误 0x8000500c)
search by samaccountname with wildcards(使用通配符按 samaccountname 搜索)
Get the list of Groups for the given UserPrincipal(获取给定 UserPrincipal 的组列表)
Can you find an Active Directory User#39;s Primary Group in C#?(你能在 C# 中找到 Active Directory 用户的主要组吗?)
Query From LDAP for User Groups(从 LDAP 查询用户组)
How can I get DOMAINUSER from an AD DirectoryEntry?(如何从 AD DirectoryEntry 获取 DOMAINUSER?)