문제

이 링크 http://msdn.microsoft.com/en-us/library/aa772153(vs.85).aspx 말 :

단일 LDAP 연결에서 최대 5 개의 알림 요청을 등록 할 수 있습니다. 알림을 기다리고 빠르게 처리하는 전용 스레드가 있어야합니다. LDAP_SEARCH_EXT 함수를 호출하여 알림 요청을 등록하면 함수는 해당 요청을 식별하는 메시지 식별자를 반환합니다. 그런 다음 ldap_result 함수를 사용하여 변경 알림을 기다립니다. 변경이 발생하면 서버는 알림을 생성 한 알림 요청에 대한 메시지 식별자가 포함 된 LDAP 메시지를 보냅니다. 이로 인해 LDAP_RESULT 기능이 변경된 객체를 식별하는 검색 결과로 돌아갑니다.

.NET 문서를 통해 비슷한 동작을 찾을 수 없습니다. C# 에서이 작업을 수행하는 방법을 아는 사람이라면 알게되어 매우 감사합니다. 변경 사항에 따라 사용자 지정 작업을 수행 할 수 있도록 속성이 시스템의 모든 사용자에 대한 속성이 언제 변경되는지보고 싶습니다.

나는 StackoverFlow와 다른 소스를 운이없는 것을 살펴 보았습니다.

감사.

도움이 되었습니까?

해결책

나는 그것이 당신이 필요로하는 것을 확실하지 않지만, http://dunnry.com/blog/implementingchangenotificationsinnet.aspx

편집 : 기사에서 텍스트와 코드가 추가되었습니다.



Active Directory (또는 Adam)에서 변경된 것들을 알아내는 세 가지 방법이 있습니다. 이것들은 적절한 제목의 MSDN에서 한동안 문서화되었습니다.변경 추적 기술의 개요 ". 요약해서 말하자면:

  1. Usnchanged를 사용한 변경에 대한 폴링. 이 기술은 'HighestCommittUsn'값을 시작하여 시작하기 위해 'usnchanged'값을 검색합니다. 'usnchanged'속성은 도메인 컨트롤러간에 복제되지 않으므로 일관성을 위해 매번 동일한 도메인 컨트롤러로 돌아 가야합니다. 본질적으로, 당신은 가장 높은 'usnchanged'value + 1을 찾는 검색을 수행 한 다음 원하는 방식으로 추적하는 결과를 읽습니다.
    • 이익
      • 이것은 가장 호환되는 방법입니다. 모든 언어와 모든 버전의 .NET은 간단한 검색이기 때문에 이러한 방식으로 지원합니다.
    • 단점
      • 개발자가 돌볼 수있는 것이 많이 있습니다. 전체 객체를 다시 얻고 객체의 변경 사항을 결정해야합니다 (그리고 그 변화에 관심이있는 경우).
      • 삭제 된 물체를 다루는 것은 고통입니다.
      • 이것은 폴링 기술이므로 쿼리 얼마나 자주 실시간으로 만 실시간입니다. 응용 프로그램에 따라 좋은 일이 될 수 있습니다. 중간 값도 여기에서 추적되지 않습니다.
  2. Dirsync Control을 사용한 변경에 대한 폴링. 이 기술은 Covers에서 ADSI 및 LDAP_SERVER_DIRSYNC_OOD 컨트롤의 ADS_SEARCHPREF_DIRSYNC 옵션을 사용합니다. 단순히 초기 검색을하고 쿠키를 저장 한 다음 나중에 다시 검색하고 쿠키를 보냅니다. 변경된 객체 만 반환합니다.
    • 이익
      • 이것은 따라갈 수있는 쉬운 모델입니다. System.DirectoryServices 및 System.DirectoryServices.Protocol 은이 옵션을 지원합니다.
      • 필터링은 귀찮게해야 할 것을 줄일 수 있습니다. 예를 들어, 초기 검색이 모든 사용자 "(ObjectClass = user)"인 경우 "(sn = dunn)"으로 폴링을 필터링하고 처리하지 않고 두 필터의 조합을 다시 얻을 수 있습니다. 세밀한 필터에서 모든 것.
      • Windows 2003+ 옵션은이 옵션 (객체 보안)을 사용하기위한 관리 제한을 제거합니다.
      • Windows 2003+ 옵션은 또한 큰 다중 값 속성에서 변경된 증분 값 만 반환 할 수있는 기능을 제공합니다. 이것은 정말 좋은 기능입니다.
      • 삭제 된 객체를 잘 처리합니다.
    • 단점
      • 이것은 .NET 2.0+ 이상 전용 옵션입니다. .NET 1.1 사용자는 USNChanged 추적을 사용해야합니다. 스크립팅 언어는이 방법을 사용할 수 없습니다.
      • 검색을 파티션으로 범위로 범위로 범위를 보일 수 있습니다. 특정 OU 또는 객체 만 추적하려면 나중에 해당 결과를 직접 분류해야합니다.
      • 이를 사용하지 않는 2003 모드 도메인과 함께 사용하면 사용할 수있는 변경 권한을 가져와야한다는 제한이 있습니다 (기본값 전용 관리자).
      • 이것은 투표 기술입니다. 중간 값도 추적하지 않습니다. 따라서 검색간에 변경 사항을 여러 번 추적하려는 객체가 마지막으로 변경됩니다. 응용 프로그램에 따라 이점이 될 수 있습니다.
  3. Active Directory에서 알림을 변경합니다. 이 기술은 필터와 일치하는 객체가 변경 될 때 알림을받을 별도의 스레드에서 검색을 등록합니다. 비동기 연결 당 최대 5 개의 알림을 등록 할 수 있습니다.
    • 이익
      • 즉각적인 알림. 다른 기술은 투표가 필요합니다.
      • 이것은 알림이므로 다른 두 가지 기술에서 손실 된 중간 변경조차도 모든 변경 사항을 얻을 수 있습니다.
    • 단점
      • 비교적 자원 집약적. 컨트롤러에서 확장 성 문제를 일으킬 수 있으므로 전체 톤을 수행하고 싶지 않습니다.
      • 이것은 객체가 변경된 경우에만 알려줍니다. 그러나 변경 사항이 무엇인지 알려주지 않습니다. 관심있는 속성이 변경되었는지 여부를 파악해야합니다. 즉, 객체가 삭제되었는지 여부를 알기가 매우 쉽습니다 (최소한 폴스 폴링보다 쉽게).
      • 관리되지 않는 코드 또는 System.DirectoryServices.Protocols에서만이 작업을 수행 할 수 있습니다.

대부분의 경우, 나는 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();
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top