2011-12-15 64 views
2

我想從活動目錄中獲取更改通知,以便我可以更新數據庫中的數據,如果在我的AD中有任何更改。我搜索了一下Ryan Dunn的good example在.NET中實現Active Directory更改通知

我試着執行他的代碼。該應用程序啓動時沒有任何錯誤,但它不會生成任何通知。有人可以幫我嗎?

我的域名是corp.am2k8vm.com,在win 2008服務器機器上,我有幾個用戶在活動目錄下進行測試。

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;} 
    } 
} 
+0

首先要考慮的是安全性。你有適當的安全性來獲取通知。接下來要考慮的是在AD中進行日誌記錄 - 也可以考慮在serverfault上詢問這些問題。我對公元二零零零年一無所知,但這是我的開始。 – 2011-12-15 22:40:32

回答

4

雖然我對你的應用程序一無所知,但我會推動你完全考慮不同的路徑。

更改通知都很好,但有一些缺點。 AD不會擴展到大量的AD。如果您在一段時間內脫機,則會錯過一些更改。等

還有另一種機制,我會鼓勵你考慮命名DirSync。將DirSync想象成AD內部複製協議的「裸露」,通過LDAP提供給您。 DirSync的想法是,您可以發出查詢並說「發生了什麼變化?」 AD會回答。與答案是一個不透明的cookie。當您下次再次發出查詢時,您會再次提供該cookie,它會告訴您發佈最後一次cookie後發生了什麼變化。

很多的這個漂亮的元素:

  • 目錄同步有一個很好的規模故事。您可以要求更改1個對象或100萬個對象,並且我們知道DirSync可以根據您的需求進行擴展。
  • DirSync有一個乾淨的故事,可以在一段時間內脫機。你可以斷開一秒鐘或一週的時間,回來並追上你錯過的一切。
  • DirSync查詢速度非常快。每分鐘發一個或類似的東西應該是一個好的。
  • DirSync有一個乾淨的多DC故事。你可以在整個數據中心使用cookie,它將(大部分)只爲你工作。 (我主要說,因爲你可能會得到dup更改,但這就是它)。或許最重要的是,DirSync有一個非常乾淨的一致性故事。我推動使用DirSync的客戶在大多數通話中執行高效的DirSync查詢,但是每隔一天(每週?每月?每月?取決於應用程序...),您可以將Cookie丟棄並完全同步。這實際上迫使你真正設計一個乾淨的e2e解決方案,始終確保你有一個很好的,安全的方式讓你的離線數據庫與AD中的事實保持一致,並且在99%以上的時間內也是有效的。而且「出錯了」的代碼路徑經過了很好的測試,因爲它是一條主線代碼路徑!它碰巧和正常的代碼路徑一樣。

假設您獲得了dup更改,您需要進行防範性編碼,但這對大多數應用程序來說是合理的假設。

希望這會有所幫助。