使用C#注册变更通知与Active Directory通知、Active、Directory

2023-09-08 12:19:56 作者:一无所有就是拼的理由

此链接 http://msdn.microsoft。 COM / EN-US /库/ aa772153(VS.85)的.aspx 说:

您最多可以注册在一个LDAP连接5通知请求。你必须有一个专用的线程等待通知,并迅速进行处理。当调用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.

我已经通过计算器和其他来源,没有运气的照顾。

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

Edit:从文章还说文字和code:

Added text and code from the article:

有三种方法计算出的事情,在活动目录(或ADAM)&NBSP发生了变化。这些都被记录了一段时间了,在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:

查询使用uSNChanged 的变化。这种技术检查highestCommittedUSN的价值开始,然后进行搜索uSNChanged值较高随后群组。在uSNChanged属性​​没有域控制器之间进行复制,所以你必须每次都回到同一个域控制器的一致性群组。从本质上讲,你执行搜索寻找最高的uSNChanged值+ 1,然后读取结果跟踪他们在你希望的任何方式。 在福利 这是最兼容的方式群组。所有语言和所有版本的.NET支持这种方式,因为它是一个简单的搜索。 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支持此选项。 过滤可以减少你需要费心群组。举个例子,如果我最初的搜索是为所有用户(对象类=用户),我可以随后筛选轮询(SN =邓恩)和​​两个滤波器的只能拿回组合,而不必处理一切从intial过滤器。 的Windows 2003+选项删除使用此选项(对象安全)的管理限制。 的Windows 2003+选项也会给你返回只在大型多值属性已经改变增量值&NBSP的能力。这是一个非常不错的功能。 优惠以及与删除的对象。 这是.NET 2.0+或更高版本唯一的选择群组。对.NET 1.1的用户需要使用uSNChanged跟踪群组。脚本语言不能使用此方法。 您只能范围搜索到一个分区 如果你想只跟踪一个特定的OU或对象时,必须理清后的结果吧。 与非Windows 2003模式域中使用此附带了您必须复制得到改变权限(默认情况下只有管理员)使用限制。 这是一个轮询技术群组。它没有任何跟踪中间值群组。所以,如果一个对象,你要跟踪的搜索多次的修改,你只会得到最后一次更改群组。这可以根据不同的应用的优点。 在福利 在即时通知群组。其它技术需要轮询。 由于这是一个通知,你会得到所有的变化,即使是中间那些会被淹没在其他两种技术。 在资源相对密集的群组。你不想做一个整体每吨这些,因为它可能会导致可扩展性问题,与控制器。 这只是告诉你,如果该对象发生了变化,但它不会告诉你什么是变化 你需要弄清楚,如果你关心的属性发生了变化或没有群组。话虽这么说,这是pretty的容易判断的对象已被删除(比uSNChanged轮询至少更容易)。 您只能在非托管code或System.DirectoryServices.Protocols做到这一点。

在大多数情况下,我发现该目录同步有适合该法案,我在几乎所有情况群组。我从来没有费心去尝试任何其他技术群组。然而,有读者问,如果有一种方法可以做到的变更通知在.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.

我在写这篇首先想到的就是使用样本code MSDN上发现(和#3选项引用),并简单地将其转换为System.DirectoryServices.Protocols群组。事实证明,这是死路一条群组。你这样做的SDS.P和方式的方式样品code的作品是不同的,以至于它是没有帮助群组。这里是我想出了一个解决方案:

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