2008-10-10 7 views
11

मैं सक्रिय निर्देशिका के माध्यम से उपयोगकर्ता की सभी सीधी रिपोर्ट प्राप्त करने की कोशिश कर रहा हूं। इसलिए उपयोगकर्ता को दिया गया, मैं उन सभी उपयोगकर्ताओं की एक सूची के साथ समाप्त हो जाऊंगा जिनके पास यह व्यक्ति प्रबंधक है या जिनके पास प्रबंधक है, जिनके पास प्रबंधक के रूप में व्यक्ति है ... अंत में इनपुट उपयोगकर्ता प्रबंधक के रूप में होता है।सक्रिय निर्देशिका से सभी प्रत्यक्ष रिपोर्ट प्राप्त करना

मेरे वर्तमान प्रयास नहीं बल्कि धीमी है:

private static Collection<string> GetDirectReportsInternal(string userDN, out long elapsedTime) 
{ 
    Collection<string> result = new Collection<string>(); 
    Collection<string> reports = new Collection<string>(); 

    Stopwatch sw = new Stopwatch(); 
    sw.Start(); 

    long allSubElapsed = 0; 
    string principalname = string.Empty; 

    using (DirectoryEntry directoryEntry = new DirectoryEntry(string.Format("LDAP://{0}",userDN))) 
    { 
     using (DirectorySearcher ds = new DirectorySearcher(directoryEntry)) 
     { 
      ds.SearchScope = SearchScope.Subtree; 
      ds.PropertiesToLoad.Clear(); 
      ds.PropertiesToLoad.Add("directReports"); 
      ds.PropertiesToLoad.Add("userPrincipalName"); 
      ds.PageSize = 10; 
      ds.ServerPageTimeLimit = TimeSpan.FromSeconds(2); 
      SearchResult sr = ds.FindOne(); 
      if (sr != null) 
      { 
       principalname = (string)sr.Properties["userPrincipalName"][0]; 
       foreach (string s in sr.Properties["directReports"]) 
       { 
        reports.Add(s); 
       } 
      } 
     } 
    } 

    if (!string.IsNullOrEmpty(principalname)) 
    { 
     result.Add(principalname); 
    } 

    foreach (string s in reports) 
    { 
     long subElapsed = 0; 
     Collection<string> subResult = GetDirectReportsInternal(s, out subElapsed); 
     allSubElapsed += subElapsed; 

     foreach (string s2 in subResult) 
     { 
     result.Add(s2); 
     } 
    } 



    sw.Stop(); 
    elapsedTime = sw.ElapsedMilliseconds + allSubElapsed; 
    return result; 
} 

मूलतः, यह समारोह इनपुट के रूप में एक प्रतिष्ठित नाम लेता है (सीएन = माइकल Stum, OU = परीक्षण, डीसी = उप, डीसी = डोमेन, डीसी = कॉम) , और उसके साथ, ds.FindOne() को कॉल धीमा है।

मुझे पता चला कि यह उपयोगकर्ता प्रिंसिपलनाम के लिए खोज करने के लिए बहुत तेज़ है। मेरी समस्या: sr.Properties ["directReports"] केवल तारों की एक सूची है, और यह विशिष्ट नाम है, जो खोज में धीमा लगता है।

मुझे आश्चर्य है, क्या प्रतिष्ठित नाम और उपयोगकर्ता प्रिंसिपलनाम के बीच परिवर्तित करने का एक तेज़ तरीका है? या क्या उपयोगकर्ता के लिए खोज करने का एक तेज़ तरीका है यदि मेरे पास केवल काम करने के लिए विशिष्ट नाम है?

संपादित करें: उत्तर के लिए धन्यवाद! प्रबंधक-फ़ील्ड को खोजना फ़ंक्शन को 90 सेकेंड से 4 सेकेंड तक बढ़ा दिया। , बंद

private static Collection<string> GetDirectReportsInternal(string ldapBase, string userDN, out long elapsedTime) 
{ 
    Collection<string> result = new Collection<string>(); 

    Stopwatch sw = new Stopwatch(); 
    sw.Start(); 
    string principalname = string.Empty; 

    using (DirectoryEntry directoryEntry = new DirectoryEntry(ldapBase)) 
    { 
     using (DirectorySearcher ds = new DirectorySearcher(directoryEntry)) 
     { 
      ds.SearchScope = SearchScope.Subtree; 
      ds.PropertiesToLoad.Clear(); 
      ds.PropertiesToLoad.Add("userPrincipalName"); 
      ds.PropertiesToLoad.Add("distinguishedName"); 
      ds.PageSize = 10; 
      ds.ServerPageTimeLimit = TimeSpan.FromSeconds(2); 
      ds.Filter = string.Format("(&(objectCategory=user)(manager={0}))",userDN); 

      using (SearchResultCollection src = ds.FindAll()) 
      { 
       Collection<string> tmp = null; 
       long subElapsed = 0; 
       foreach (SearchResult sr in src) 
       { 
        result.Add((string)sr.Properties["userPrincipalName"][0]); 
        tmp = GetDirectReportsInternal(ldapBase, (string)sr.Properties["distinguishedName"][0], out subElapsed); 
        foreach (string s in tmp) 
        { 
        result.Add(s); 
        } 
       } 
      } 
      } 
     } 
    sw.Stop(); 
    elapsedTime = sw.ElapsedMilliseconds; 
    return result; 
} 
+0

आप निर्देशिका एंटर्री और निर्देशिका खोजकर्ता को रिकर्सन से बाहर ले कर अतिरिक्त गति प्राप्त कर सकते हैं। वे बीच में नहीं बदलते हैं, क्या वे करते हैं? – Tomalak

+0

अब और नहीं। मैंने जो नहीं कहा: मैं इसे एक शेयरपॉइंट एनवायरनमेंट में उपयोग कर रहा हूं जहां कॉल को एसपीएस सुरक्षा में लपेटा जाता है। RunWithElevatedPrivileges कॉल, जिसका अर्थ है कि रेफ पैरामीटर्स संभव नहीं हैं, और मुझे यकीन नहीं है कि इसे सामान्य पैरामीटर काम के रूप में पास करना (अजीब शेयरपॉइंट सुरक्षा) –

+0

मुझे लगता है कि यह काम करना चाहिए। वस्तुओं को हमेशा रेफरी, AFAIK के रूप में पारित किया जाता है। देखें: http://stackoverflow.com/questions/186891/why-use-ref-keyword-when-passing-an-object – Tomalak

उत्तर

10

पहले स्कोप की स्थापना: यहाँ नए और बेहतर कोड है, जो तेजी से और अधिक पठनीय है (ध्यान दें कि सबसे अधिक संभावना elapsedTime कार्यक्षमता में एक बग है कि है, लेकिन समारोह के वास्तविक मूल काम करता है) "subtree" के लिए अनावश्यक है जब आपके पास पहले से ही डीएन है जिसे आप ढूंढ रहे हैं।

इसके अलावा, उन सभी वस्तुओं को खोजने के बारे में, जिनके "प्रबंधक" संपत्ति वह व्यक्ति है जिसे आप ढूंढते हैं, फिर उन्हें पुन: सक्रिय करते हैं। यह आम तौर पर आसपास के दूसरे तरीके से तेज होना चाहिए।

(&(objectCategory=user)(manager=<user-dn-here>)) 

संपादित करें: निम्नलिखित महत्वपूर्ण है, लेकिन केवल इस उत्तर के अब तक के लिए टिप्पणी में उल्लेख किया गया है:

जब फिल्टर स्ट्रिंग के रूप में ऊपर संकेत बनाया गया है, वहाँ यह तोड़ने का खतरा है उन वर्णों के साथ जो डीएन के लिए मान्य हैं, लेकिन फ़िल्टर में विशेष अर्थ है। ये must be escaped:

* as \2a 
( as \28 
) as \29 
\ as \5c 
NUL as \00 
/ as \2f 

// Arbitrary binary data can be represented using the same scheme. 

संपादित करें: एक वस्तु का डी एन के SearchRoot, और Base को SearchScope स्थापना भी एक तेजी से ई से बाहर एक वस्तु को खींचने के लिए तरीका है।

+0

धन्यवाद। मैं देखता हूं कि यह सबट्री के बिना कैसे करता है। आपके दूसरे सुझाव के लिए, यह दिलचस्प लगता है। मुझे अपने मस्तिष्क को थोड़ा सा लपेटने की ज़रूरत है क्योंकि फ़ंक्शन को अभी भी रिकर्सिव होने की आवश्यकता है, लेकिन मैं तुरंत इसका परीक्षण करूंगा। –

+1

अगर मैं आपको 10 बार वोट दे सकता हूं, तो मैं ऐसा करूँगा। मैनेजर की तलाश करने के लिए फ़ंक्शन को चेजेट करने से इसे 90 सेकंड्स से केवल 4 सेकंड तक चलने में सुधार हुआ। –

+0

सावधान रहें कि उस दृष्टिकोण के साथ, आपको अपने फ़िल्टर स्ट्रिंग को उन वर्णों के साथ तोड़ने का जोखिम माइग्रेट करना होगा जो एक डीएन में मान्य हैं लेकिन फ़िल्टर स्ट्रिंग में आरक्षित हैं। मेरे सिर के शीर्ष पर, कम से कम '#' से बचने की जरूरत है। – Tomalak