<?xml version="1.0" encoding="UTF-8"?><rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
> <channel><title>Comments on: How a simple foreach statement can waste an afternoon</title> <atom:link href="http://davybrion.com/blog/2008/05/how-a-simple-foreach-statement-can-waste-an-afternoon/feed/" rel="self" type="application/rss+xml" /><link>http://davybrion.com/blog/2008/05/how-a-simple-foreach-statement-can-waste-an-afternoon/</link> <description>inquisitive: adjective. given to inquiry, research, or asking questions; eager for knowledge; intellectually curious</description> <lastBuildDate>Wed, 16 May 2012 15:43:00 +0000</lastBuildDate> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.2</generator> <item><title>By: Davy Brion</title><link>http://davybrion.com/blog/2008/05/how-a-simple-foreach-statement-can-waste-an-afternoon/comment-page-1/#comment-24407</link> <dc:creator>Davy Brion</dc:creator> <pubDate>Sun, 10 Jan 2010 13:07:00 +0000</pubDate> <guid
isPermaLink="false">http://davybrion.com/blog/?p=128#comment-24407</guid> <description>@Lucexcellent stuff... i no longer have access to that particular application because i&#039;m not working at that client anymore, but i&#039;ll definitely use this if i do any future AD work :)</description> <content:encoded><![CDATA[<p>@Luc</p><p>excellent stuff&#8230; i no longer have access to that particular application because i&#8217;m not working at that client anymore, but i&#8217;ll definitely use this if i do any future AD work <img
src='http://d18sni7re4ly7f.cloudfront.net/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p> ]]></content:encoded> </item> <item><title>By: Luc</title><link>http://davybrion.com/blog/2008/05/how-a-simple-foreach-statement-can-waste-an-afternoon/comment-page-1/#comment-24405</link> <dc:creator>Luc</dc:creator> <pubDate>Sun, 10 Jan 2010 13:02:32 +0000</pubDate> <guid
isPermaLink="false">http://davybrion.com/blog/?p=128#comment-24405</guid> <description>Davy,Yes, you can retrieve all members in a AD group with one LDAP request and suppress request roundtrips to the AD.
I don&#039;t know your application, but my experience is that using the DirectorySearcher class in such situations has some advantages.1. You can work with disconnected search results
2. By specifying the attributes in which you are interested in, you can limit the amount of data transported between the AD and the application.
3. You can use Attribute scope queries. This might be important for your application.
Example: when your are interested in for example the e-mail addresses of the users in a group (or distribution list), you can use the group as root for the directory search, but specify which objects (and which attributes, in this case mail address) you want to return based on an attribute (in this case &#039;member&#039;) of the search root. As such the search root must not be transported to the application, and the results which may be spread around in the AD can be retrieved whithout any navigation.When accessing AD from .NET, following thing are imho important:
- Choose the correct root object.
- Use disconnected model if possible.
- Be specific about attributes you want to access
- Use the correct scoping (Base, OneLevel or Subtree)
- Avoid sorting
- Use indexed attributes in filters
- Do not treat AD as a classic relational database, it isn&#039;t one. So learn LDAP queriesExample code:static void Main(string[] args)
{
string[] attribs = new string[]{&quot;distinguishedName&quot;, &quot;sAMAccountName&quot;, &quot;name&quot;, &quot;mail&quot;};
DirectoryEntry users = new DirectoryEntry(&quot;LDAP://S2008:389/CN=Users,DC=lvk,DC=local&quot;,
@&quot;User&quot;, &quot;Password&quot;, AuthenticationTypes.Secure);DirectorySearcher ds = new DirectorySearcher(users, &quot;(objectClass=group)&quot;,
new string[] { &quot;distinguishedName&quot; ,&quot;member&quot;});
ds.CacheResults = true;using (SearchResultCollection src = ds.FindAll())
{
Console.WriteLine(&quot;Returning {0}&quot;, src.Count);foreach (SearchResult sr in src)
{
Console.WriteLine(&quot;Processing group:{0}&quot;, sr.Properties[&quot;distinguishedName&quot;][0]);DirectorySearcher ds2 = new DirectorySearcher(sr.GetDirectoryEntry(),
&quot;(&amp;(objectClass=user)(objectCategory=person))&quot;, attribs);
ds2.SearchScope = SearchScope.Base;
ds2.AttributeScopeQuery = &quot;member&quot;;
ds2.CacheResults = true;using (SearchResultCollection src2 = ds2.FindAll())
{
foreach (SearchResult sr2 in src2)
{
foreach (string s in attribs)
{
if (sr2.Properties.Contains(s) &amp;&amp; sr2.Properties[s].Count &gt; 0)
{
Console.WriteLine(&quot;{0}: {1}&quot;, s, sr2.Properties[s][0]);
}
}
Console.WriteLine();
}
}
Console.WriteLine(&quot;--------------------------------------------------------------------&quot;);
}
}
Console.ReadLine();
}If you use a sniffer, you should see that all the members in a group (and the requested attributes) are retrieved with one LDAP query.</description> <content:encoded><![CDATA[<p>Davy,</p><p>Yes, you can retrieve all members in a AD group with one LDAP request and suppress request roundtrips to the AD.<br
/> I don&#8217;t know your application, but my experience is that using the DirectorySearcher class in such situations has some advantages.</p><p>1. You can work with disconnected search results<br
/> 2. By specifying the attributes in which you are interested in, you can limit the amount of data transported between the AD and the application.<br
/> 3. You can use Attribute scope queries. This might be important for your application.<br
/> Example: when your are interested in for example the e-mail addresses of the users in a group (or distribution list), you can use the group as root for the directory search, but specify which objects (and which attributes, in this case mail address) you want to return based on an attribute (in this case &#8216;member&#8217;) of the search root. As such the search root must not be transported to the application, and the results which may be spread around in the AD can be retrieved whithout any navigation.</p><p>When accessing AD from .NET, following thing are imho important:<br
/> - Choose the correct root object.<br
/> - Use disconnected model if possible.<br
/> - Be specific about attributes you want to access<br
/> - Use the correct scoping (Base, OneLevel or Subtree)<br
/> - Avoid sorting<br
/> - Use indexed attributes in filters<br
/> - Do not treat AD as a classic relational database, it isn&#8217;t one. So learn LDAP queries</p><p>Example code:</p><p> static void Main(string[] args)<br
/> {<br
/> string[] attribs = new string[]{&#8220;distinguishedName&#8221;, &#8220;sAMAccountName&#8221;, &#8220;name&#8221;, &#8220;mail&#8221;};<br
/> DirectoryEntry users = new DirectoryEntry(&#8220;LDAP://S2008:389/CN=Users,DC=lvk,DC=local&#8221;,<br
/> @&#8221;User&#8221;, &#8220;Password&#8221;, AuthenticationTypes.Secure);</p><p> DirectorySearcher ds = new DirectorySearcher(users, &#8220;(objectClass=group)&#8221;,<br
/> new string[] { &#8220;distinguishedName&#8221; ,&#8221;member&#8221;});<br
/> ds.CacheResults = true;</p><p> using (SearchResultCollection src = ds.FindAll())<br
/> {<br
/> Console.WriteLine(&#8220;Returning {0}&#8221;, src.Count);</p><p> foreach (SearchResult sr in src)<br
/> {<br
/> Console.WriteLine(&#8220;Processing group:{0}&#8221;, sr.Properties["distinguishedName"][0]);</p><p> DirectorySearcher ds2 = new DirectorySearcher(sr.GetDirectoryEntry(),<br
/> &#8220;(&amp;(objectClass=user)(objectCategory=person))&#8221;, attribs);<br
/> ds2.SearchScope = SearchScope.Base;<br
/> ds2.AttributeScopeQuery = &#8220;member&#8221;;<br
/> ds2.CacheResults = true;</p><p> using (SearchResultCollection src2 = ds2.FindAll())<br
/> {<br
/> foreach (SearchResult sr2 in src2)<br
/> {<br
/> foreach (string s in attribs)<br
/> {<br
/> if (sr2.Properties.Contains(s) &amp;&amp; sr2.Properties[s].Count &gt; 0)<br
/> {<br
/> Console.WriteLine(&#8220;{0}: {1}&#8221;, s, sr2.Properties[s][0]);<br
/> }<br
/> }<br
/> Console.WriteLine();<br
/> }<br
/> }<br
/> Console.WriteLine(&#8220;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;&#8221;);<br
/> }<br
/> }<br
/> Console.ReadLine();<br
/> }</p><p>If you use a sniffer, you should see that all the members in a group (and the requested attributes) are retrieved with one LDAP query.</p> ]]></content:encoded> </item> <item><title>By: Davy Brion</title><link>http://davybrion.com/blog/2008/05/how-a-simple-foreach-statement-can-waste-an-afternoon/comment-page-1/#comment-288</link> <dc:creator>Davy Brion</dc:creator> <pubDate>Fri, 30 May 2008 04:56:20 +0000</pubDate> <guid
isPermaLink="false">http://davybrion.com/blog/?p=128#comment-288</guid> <description>Depending on how GroupPrincipal.Dispose is implemented, that might not release every reference the instance uses. If i only call Dispose without removing it from the list, i&#039;ll still hold a reference to it, and it won&#039;t be eligible for garbage collection even though it will indeed use less memory already due to the call to Dispose.I&#039;d need to look at the GroupPrincipal.Dispose method in reflector to be sure, but i&#039;d rather dispose it and get rid of the reference entirely once i no longer need it, especially if we&#039;re talking about a loop that still takes a few minutes.</description> <content:encoded><![CDATA[<p>Depending on how GroupPrincipal.Dispose is implemented, that might not release every reference the instance uses. If i only call Dispose without removing it from the list, i&#8217;ll still hold a reference to it, and it won&#8217;t be eligible for garbage collection even though it will indeed use less memory already due to the call to Dispose.</p><p>I&#8217;d need to look at the GroupPrincipal.Dispose method in reflector to be sure, but i&#8217;d rather dispose it and get rid of the reference entirely once i no longer need it, especially if we&#8217;re talking about a loop that still takes a few minutes.</p> ]]></content:encoded> </item> <item><title>By: Marc Brooks</title><link>http://davybrion.com/blog/2008/05/how-a-simple-foreach-statement-can-waste-an-afternoon/comment-page-1/#comment-286</link> <dc:creator>Marc Brooks</dc:creator> <pubDate>Thu, 29 May 2008 23:23:15 +0000</pubDate> <guid
isPermaLink="false">http://davybrion.com/blog/?p=128#comment-286</guid> <description>You realize that the exact symptom you are running into can simply be handled in the original code by calling the groupPrinciple.Dispose() method at the end of the loop.  You&#039;re not changing the collection (which would assert), you&#039;re changing the objects it points at.</description> <content:encoded><![CDATA[<p>You realize that the exact symptom you are running into can simply be handled in the original code by calling the groupPrinciple.Dispose() method at the end of the loop.  You&#8217;re not changing the collection (which would assert), you&#8217;re changing the objects it points at.</p> ]]></content:encoded> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: enhanced
Database Caching 1/12 queries in 0.006 seconds using disk: basic
Object Caching 374/451 objects using disk: basic
Content Delivery Network via Amazon Web Services: CloudFront: d18sni7re4ly7f.cloudfront.net

Served from: davybrion.com @ 2012-05-17 11:34:39 -->
