<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Extemporaneous Mumblings - .NET</title>
    <link>http://dunnry.com/blog/</link>
    <description>... a blog by Ryan Dunn</description>
    <language>en-us</language>
    <copyright>Ryan Dunn</copyright>
    <lastBuildDate>Thu, 04 Sep 2008 21:32:11 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.3.9074.18820</generator>
    <managingEditor>ryan@dunnry.com</managingEditor>
    <webMaster>ryan@dunnry.com</webMaster>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=235f429b-cc1c-438e-80d6-49f8884e0336</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,235f429b-cc1c-438e-80d6-49f8884e0336.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,235f429b-cc1c-438e-80d6-49f8884e0336.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=235f429b-cc1c-438e-80d6-49f8884e0336</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
We have just released an updated version of the SSDS sample application called 'PhluffyFotos'. 
Clouds are fluffy and this is a cloud services application - get it?  This sample
application is a ASP.NET MVC and Windows Mobile application showing how to build a
photo tagging and sharing site using our cloud data service, SSDS.  For this
update:
</p>
        <ul>
          <li>
Updated to MVC Preview 4.  We have removed hardcoded links and used the new filtering
capability for authorization.  Of course, Preview 5 was just (and just) released
as we were putting this out the door.  I might update this to Preview 5 later,
but it will not be a big deal to do so.  
</li>
          <li>
Updated to add thumbnail support.  Originally, we just downloaded the entire
image and resized to thumbnail size.  This drags down performance in larger data
sizes, so we fixed it for this release. 
</li>
          <li>
Updated to use the SSDS blob support.  Blob support was recently added with the
latest sprint.  Previously, we were using the 'base64Binary' attributes to store
the picture data.  With the new blob support, you supply a content type and content
disposition, which will be streamed back to you on request.  
</li>
          <li>
Updated to use the latest <a href="http://code.msdn.com/ssdsrest">SSDS REST library</a>. 
This library gives us the ability to use and persist CLR objects to the service and
use a LINQ-like query syntax.  This library saved us a ton of time and effort
in building the actual application.  All the blob work, querying, and data access
was done using this library.</li>
        </ul>
        <p>
The sample is available for download at <a href="http://www.codeplex.com/phluffyfotos">CodePlex</a>,
and a live version is available to play with at <a href="http://www.phluffyfotos.com">PhluffyFotos.com</a>. 
I am opening this one up to the public to upload photos.  Maybe I am playing
with fire here, so we will see how well it goes.  Keep in mind that this is a
sample site and I will periodically blow away the data.  The live version has
an added feature of integrating a source code viewer directly into the application.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=235f429b-cc1c-438e-80d6-49f8884e0336" />
      </body>
      <title>PhluffyFotos v2 Released</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,235f429b-cc1c-438e-80d6-49f8884e0336.aspx</guid>
      <link>http://dunnry.com/blog/2008/09/04/PhluffyFotosV2Released.aspx</link>
      <pubDate>Thu, 04 Sep 2008 21:32:11 GMT</pubDate>
      <description>&lt;p&gt;
We have just released an updated version of the SSDS sample application called 'PhluffyFotos'.&amp;nbsp;
Clouds are fluffy and this is a cloud services application - get it?&amp;nbsp; This sample
application is a ASP.NET MVC and Windows Mobile application showing how to build a
photo tagging and sharing site using our cloud data service, SSDS.&amp;nbsp; For this
update:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Updated to MVC Preview 4.&amp;nbsp; We have removed hardcoded links and used the new filtering
capability for authorization.&amp;nbsp; Of course, Preview 5 was just (and just) released
as we were putting this out the door.&amp;nbsp; I might update this to Preview 5 later,
but it will not be a big deal to do so.&amp;nbsp; 
&lt;li&gt;
Updated to add thumbnail support.&amp;nbsp; Originally, we just downloaded the entire
image and resized to thumbnail size.&amp;nbsp; This drags down performance in larger data
sizes, so we fixed it for this release. 
&lt;li&gt;
Updated to use the SSDS blob support.&amp;nbsp; Blob support was recently added with the
latest sprint.&amp;nbsp; Previously, we were using the 'base64Binary' attributes to store
the picture data.&amp;nbsp; With the new blob support, you supply a content type and content
disposition, which will be streamed back to you on request.&amp;nbsp; 
&lt;li&gt;
Updated to use the latest &lt;a href="http://code.msdn.com/ssdsrest"&gt;SSDS REST library&lt;/a&gt;.&amp;nbsp;
This library gives us the ability to use and persist CLR objects to the service and
use a LINQ-like query syntax.&amp;nbsp; This library saved us a ton of time and effort
in building the actual application.&amp;nbsp; All the blob work, querying, and data access
was done using this library.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
The sample is available for download at &lt;a href="http://www.codeplex.com/phluffyfotos"&gt;CodePlex&lt;/a&gt;,
and a live version is available to play with at &lt;a href="http://www.phluffyfotos.com"&gt;PhluffyFotos.com&lt;/a&gt;.&amp;nbsp;
I am opening this one up to the public to upload photos.&amp;nbsp; Maybe I am playing
with fire here, so we will see how well it goes.&amp;nbsp; Keep in mind that this is a
sample site and I will periodically blow away the data.&amp;nbsp; The live version has
an added feature of integrating a source code viewer directly into the application.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=235f429b-cc1c-438e-80d6-49f8884e0336" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,235f429b-cc1c-438e-80d6-49f8884e0336.aspx</comments>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Cloud Services</category>
      <category>SSDS</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=3164369c-5fe5-475f-af56-70e82301c91a</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,3164369c-5fe5-475f-af56-70e82301c91a.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,3164369c-5fe5-475f-af56-70e82301c91a.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=3164369c-5fe5-475f-af56-70e82301c91a</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I have just updated the <a href="http://code.msdn.microsoft.com/ssdsrest">Code Gallery
page</a> to reflect the new version of the REST-based library for SSDS.  This
is a fairly major update to library and adds a ton of new features to make working
with SSDS even easier than it already is for the .NET developer.  Added in this
release:
</p>
        <ul>
          <li>
Concurrency support via Etags and If-Match, If-None-Match headers.  To get a
basic understanding of how this works, <a href="http://dunnry.com/blog/ConcurrencyWithSSDSViaREST.aspx">refer
here</a>. 
</li>
          <li>
Blob support.  The library introduces a new type called <strong>SsdsBlobEntity</strong> that
encapsulates working with blobs in SSDS.  Overloads are available for both synchronous
as well as async support. 
</li>
          <li>
Parallelization support via extension methods.  The jury is still out on this
one and I would like to hear some feedback on it (both the technique as well as the
methods).  Instead of using an interface, factory methods, etc., we are using
extension methods supplied in a separate assembly to support parallel operations. 
Since there are many different techniques to parallelize your code, this allows us
to offer more than one option.  Each additional assembly can also take dependencies
that the entire library might not want to take as well.  Imagine that we get
providers for Parallel Extensions, CCR, or perhaps other home-baked remedies. 
A very simple provider using Parallel Extensions is included. 
</li>
          <li>
Bug fixes.  Hard to believe, but yes, I did have a few bugs in my code. 
This release cleans up a few of the ones found in the LINQ expression syntax parser
as well as a few oversights in handling date/times. 
</li>
          <li>
Better test coverage.  Lots more tests included to not only prove out that stuff
works, but also to show how to use it.</li>
        </ul>
        <p>
If you just want to see this library in action, refer to the photo sharing and tagging
application called <a href="http://www.phluffyfotos.com/">'PhluffyFotos'</a> that
pulls it all together (sans parallelization, I suppose).  You can use the integrated
source viewer to see how the library works on a 'real' application (or a real sample
application at least).
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=3164369c-5fe5-475f-af56-70e82301c91a" />
      </body>
      <title>SSDS REST Library v2 Released</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,3164369c-5fe5-475f-af56-70e82301c91a.aspx</guid>
      <link>http://dunnry.com/blog/2008/09/04/SSDSRESTLibraryV2Released.aspx</link>
      <pubDate>Thu, 04 Sep 2008 20:25:41 GMT</pubDate>
      <description>&lt;p&gt;
I have just updated the &lt;a href="http://code.msdn.microsoft.com/ssdsrest"&gt;Code Gallery
page&lt;/a&gt; to reflect the new version of the REST-based library for SSDS.&amp;nbsp; This
is a fairly major update to library and adds a ton of new features to make working
with SSDS even easier than it already is for the .NET developer.&amp;nbsp; Added in this
release:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Concurrency support via Etags and If-Match, If-None-Match headers.&amp;nbsp; To get a
basic understanding of how this works, &lt;a href="http://dunnry.com/blog/ConcurrencyWithSSDSViaREST.aspx"&gt;refer
here&lt;/a&gt;. 
&lt;li&gt;
Blob support.&amp;nbsp; The library introduces a new type called &lt;strong&gt;SsdsBlobEntity&lt;/strong&gt; that
encapsulates working with blobs in SSDS.&amp;nbsp; Overloads are available for both synchronous
as well as async support. 
&lt;li&gt;
Parallelization support via extension methods.&amp;nbsp; The jury is still out on this
one and I would like to hear some feedback on it (both the technique as well as the
methods).&amp;nbsp; Instead of using an interface, factory methods, etc., we are using
extension methods supplied in a separate assembly to support parallel operations.&amp;nbsp;
Since there are many different techniques to parallelize your code, this allows us
to offer more than one option.&amp;nbsp; Each additional assembly can also take dependencies
that the entire library might not want to take as well.&amp;nbsp; Imagine that we get
providers for Parallel Extensions, CCR, or perhaps other home-baked remedies.&amp;nbsp;
A very simple provider using Parallel Extensions is included. 
&lt;li&gt;
Bug fixes.&amp;nbsp; Hard to believe, but yes, I did have a few bugs in my code.&amp;nbsp;
This release cleans up a few of the ones found in the LINQ expression syntax parser
as well as a few oversights in handling date/times. 
&lt;li&gt;
Better test coverage.&amp;nbsp; Lots more tests included to not only prove out that stuff
works, but also to show how to use it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
If you just want to see this library in action, refer to the photo sharing and tagging
application called &lt;a href="http://www.phluffyfotos.com/"&gt;'PhluffyFotos'&lt;/a&gt; that
pulls it all together (sans parallelization, I suppose).&amp;nbsp; You can use the integrated
source viewer to see how the library works on a 'real' application (or a real sample
application at least).
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=3164369c-5fe5-475f-af56-70e82301c91a" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,3164369c-5fe5-475f-af56-70e82301c91a.aspx</comments>
      <category>.NET</category>
      <category>Cloud Services</category>
      <category>SSDS</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=327be3af-bb56-4aec-ad53-149dad9082c2</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,327be3af-bb56-4aec-ad53-149dad9082c2.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,327be3af-bb56-4aec-ad53-149dad9082c2.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=327be3af-bb56-4aec-ad53-149dad9082c2</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Eugenio already covered concurrency via the SOAP interface with with <a href="http://blogs.msdn.com/eugeniop/archive/2008/08/01/concurrency-in-ssds.aspx">latest
post</a>.  The idea is exactly the same in REST, but the mechanics are slightly
different.  For REST, you specify a "Etag" value and either the If-Match or If-None-Match
headers.
</p>
        <p>
Here is a simplified client that does a PUT/POST operation on SSDS:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">internal</span>
            <span style="color: #0000ff">void</span> Send(Uri
scope, <span style="color: #0000ff">string</span> etag, <span style="color: #0000ff">string</span> method, <span style="color: #0000ff">string</span> data,
Action&lt;<span style="color: #0000ff">string</span>, WebHeaderCollection&gt; action,
Action&lt;WebException&gt; exception) { <span style="color: #0000ff">using</span> (var
client = <span style="color: #0000ff">new</span> WebClient { Credentials = _credentials
}) { client.Headers.Add(HttpRequestHeader.ContentType, <span style="color: #006080">"application/x-ssds+xml"</span>); <span style="color: #0000ff">if</span> (etag
!= <span style="color: #0000ff">null</span>) client.Headers.Add(HttpRequestHeader.IfMatch,
etag); client.UploadStringCompleted += (sender, e) =&gt; { <span style="color: #0000ff">if</span> (e.Error
!= <span style="color: #0000ff">null</span> &amp;&amp; exception != <span style="color: #0000ff">null</span>)
{ exception((WebException)e.Error); } <span style="color: #0000ff">else</span> { <span style="color: #0000ff">if</span> (action
!= <span style="color: #0000ff">null</span>) { action(e.Result, client.ResponseHeaders);
} } }; client.UploadStringAsync(scope, method, data); } }</pre>
        </div>
        <p>
 
</p>
        <p>
All this does is add the If-Match header and the Etag (which corresponds to the Flexible
Entity Version system attribute).  This instructs the system to only update if
the version held in SSDS matches the version specified in the Etag with the If-Match
header.
</p>
        <p>
Failure of this condition will result in a <strong>412</strong> error "<em>A precondition,
such as Version, could not be met</em>".  You simply need to handle this exception
and move on.
</p>
        <p>
Next, there are times when you have a large blob or a largish flexible entity. 
You only want to perform the GET if you don't have the latest version.  In this
case, you specify the Etag again with the If-None-Match header.
</p>
        <p>
Here is a simplified client that shows how the GET would work:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">public</span>
            <span style="color: #0000ff">void</span> Get(Uri
scope, <span style="color: #0000ff">string</span> etag, Action&lt;<span style="color: #0000ff">string</span>,
WebHeaderCollection&gt; action, Action&lt;WebException&gt; exception) { <span style="color: #0000ff">using</span> (var
client = <span style="color: #0000ff">new</span> WebClient { Credentials = _credentials
}) { client.Headers.Add(HttpRequestHeader.ContentType, <span style="color: #006080">"application/x-ssds+xml"</span>); <span style="color: #0000ff">if</span> (etag
!= <span style="color: #0000ff">null</span>) client.Headers.Add(HttpRequestHeader.IfNoneMatch,
etag); client.DownloadStringCompleted += (sender, e) =&gt; { <span style="color: #0000ff">if</span> (e.Error
!= <span style="color: #0000ff">null</span> &amp;&amp; exception != <span style="color: #0000ff">null</span>)
{ exception((WebException)e.Error); } <span style="color: #0000ff">else</span> { <span style="color: #0000ff">if</span> (action
!= <span style="color: #0000ff">null</span>) action(e.Result, client.ResponseHeaders);
} }; client.DownloadStringAsync(scope); } </pre>
        </div>
        <p>
When you add the Etag and this header, you will receive a <strong>304</strong> error
"<em>Not Modified</em>" if the content has NOT changed since the Etag value you sent.
</p>
        <p>
I am attaching a small <a href="http://cid-4225352e17899c6d.skydrive.live.com/self.aspx/Public/Concurrency.zip">Visual
Studio sample</a> that includes this code and demonstrates these techniques.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=327be3af-bb56-4aec-ad53-149dad9082c2" />
      </body>
      <title>Concurrency with SSDS via REST</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,327be3af-bb56-4aec-ad53-149dad9082c2.aspx</guid>
      <link>http://dunnry.com/blog/2008/08/26/ConcurrencyWithSSDSViaREST.aspx</link>
      <pubDate>Tue, 26 Aug 2008 17:30:11 GMT</pubDate>
      <description>&lt;p&gt;
Eugenio already covered concurrency via the SOAP interface with with &lt;a href="http://blogs.msdn.com/eugeniop/archive/2008/08/01/concurrency-in-ssds.aspx"&gt;latest
post&lt;/a&gt;.&amp;nbsp; The idea is exactly the same in REST, but the mechanics are slightly
different.&amp;nbsp; For REST, you specify a "Etag" value and either the If-Match or If-None-Match
headers.
&lt;/p&gt;
&lt;p&gt;
Here is a simplified client that does a PUT/POST operation on SSDS:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Send(Uri
scope, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; etag, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; method, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; data,
Action&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, WebHeaderCollection&amp;gt; action,
Action&amp;lt;WebException&amp;gt; exception) { &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (var
client = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; WebClient { Credentials = _credentials
}) { client.Headers.Add(HttpRequestHeader.ContentType, &lt;span style="color: #006080"&gt;"application/x-ssds+xml"&lt;/span&gt;); &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (etag
!= &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) client.Headers.Add(HttpRequestHeader.IfMatch,
etag); client.UploadStringCompleted += (sender, e) =&amp;gt; { &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (e.Error
!= &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; exception != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)
{ exception((WebException)e.Error); } &lt;span style="color: #0000ff"&gt;else&lt;/span&gt; { &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (action
!= &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) { action(e.Result, client.ResponseHeaders);
} } }; client.UploadStringAsync(scope, method, data); } }&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
All this does is add the If-Match header and the Etag (which corresponds to the Flexible
Entity Version system attribute).&amp;nbsp; This instructs the system to only update if
the version held in SSDS matches the version specified in the Etag with the If-Match
header.
&lt;/p&gt;
&lt;p&gt;
Failure of this condition will result in a &lt;strong&gt;412&lt;/strong&gt; error "&lt;em&gt;A precondition,
such as Version, could not be met&lt;/em&gt;".&amp;nbsp; You simply need to handle this exception
and move on.
&lt;/p&gt;
&lt;p&gt;
Next, there are times when you have a large blob or a largish flexible entity.&amp;nbsp;
You only want to perform the GET if you don't have the latest version.&amp;nbsp; In this
case, you specify the Etag again with the If-None-Match header.
&lt;/p&gt;
&lt;p&gt;
Here is a simplified client that shows how the GET would work:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Get(Uri
scope, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; etag, Action&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;,
WebHeaderCollection&amp;gt; action, Action&amp;lt;WebException&amp;gt; exception) { &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (var
client = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; WebClient { Credentials = _credentials
}) { client.Headers.Add(HttpRequestHeader.ContentType, &lt;span style="color: #006080"&gt;"application/x-ssds+xml"&lt;/span&gt;); &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (etag
!= &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) client.Headers.Add(HttpRequestHeader.IfNoneMatch,
etag); client.DownloadStringCompleted += (sender, e) =&amp;gt; { &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (e.Error
!= &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; exception != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)
{ exception((WebException)e.Error); } &lt;span style="color: #0000ff"&gt;else&lt;/span&gt; { &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (action
!= &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) action(e.Result, client.ResponseHeaders);
} }; client.DownloadStringAsync(scope); } &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
When you add the Etag and this header, you will receive a &lt;strong&gt;304&lt;/strong&gt; error
"&lt;em&gt;Not Modified&lt;/em&gt;" if the content has NOT changed since the Etag value you sent.
&lt;/p&gt;
&lt;p&gt;
I am attaching a small &lt;a href="http://cid-4225352e17899c6d.skydrive.live.com/self.aspx/Public/Concurrency.zip"&gt;Visual
Studio sample&lt;/a&gt; that includes this code and demonstrates these techniques.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=327be3af-bb56-4aec-ad53-149dad9082c2" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,327be3af-bb56-4aec-ad53-149dad9082c2.aspx</comments>
      <category>.NET</category>
      <category>Cloud Services</category>
      <category>SSDS</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=b37072b9-1fe8-4785-9df3-00861ab346f7</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,b37072b9-1fe8-4785-9df3-00861ab346f7.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,b37072b9-1fe8-4785-9df3-00861ab346f7.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=b37072b9-1fe8-4785-9df3-00861ab346f7</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Here is my last installment in this series of working with objects in SQL Server Data
Services.  For background, readers should read the following:
</p>
        <p>
          <a href="http://dunnry.com/blog/SerializationInSSDS.aspx">Serialization in SSDS</a>
        </p>
        <p>
          <a href="http://dunnry.com/blog/WorkingWithObjectsInSSDSPart1.aspx">Working with Objects
in SSDS Part 1</a>
        </p>
        <p>
          <a href="http://dunnry.com/blog/WorkingWithObjectsInSSDSPart2.aspx">Working with Objects
in SSDS Part 2</a>
        </p>
        <p>
Last time, we concluded with a class called <strong>SsdsEntity&lt;T&gt;</strong> that
became an all-purpose wrapper or veneer around our CLR objects.  This made it
simple to take our existing classes and serialize them as entities in SSDS.
</p>
        <p>
In this post, I want to discuss how the querying in the REST library works. 
First a simple example:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">var ctx = <span style="color: #0000ff">new</span> SsdsContext( <span style="color: #006080">"authority=http://dunnry.data.beta.mssds.com/v1/;username=dunnry;password=secret"</span> );
var container = ctx.OpenContainer(<span style="color: #006080">"foo"</span>); var
foo = <span style="color: #0000ff">new</span> Foo { IsPublic = <span style="color: #0000ff">false</span>,
Name = <span style="color: #006080">"MyFoo"</span>, Size = 12 }; <span style="color: #008000">//insert
it with unique id guid string</span> container.Insert(foo, Guid.NewGuid().ToString()); <span style="color: #008000">//now
query for it</span> var results = container.Query&lt;Foo&gt;(e =&gt; e.Entity.IsPublic
== <span style="color: #0000ff">false</span> &amp;&amp; e.Entity.Size &gt; 2); <span style="color: #008000">//Query&lt;T&gt;
returns IEnumerable&lt;SsdsEntity&lt;T&gt;&gt;, so foreach over it</span><span style="color: #0000ff">foreach</span> (var
item <span style="color: #0000ff">in</span> results) { Console.WriteLine(item.Entity.Name);
}</pre>
        </div>
        <p>
I glossed over it in my previous posts with this library, but I have a class called <strong>SsdsContext</strong> that
acts as my credential store and factory to create <strong>SsdsContainer</strong> objects
where I perform my operations.  Here, I have opened a container called 'foo',
which would relate to the URI (<a href="http://dunnry.data.beta.mssds.com/v1/foo">http://dunnry.data.beta.mssds.com/v1/foo</a>)
according to the authority name I passed on the <strong>SsdsContext</strong> constructor
arguments.
</p>
        <p>
I created an instance of my <strong>Foo</strong> class (see <a href="http://dunnry.com/blog/WorkingWithObjectsInSSDSPart1.aspx">this
post</a> if you want to see what a <strong>Foo</strong> looks like) and inserted it. 
We know that under the covers we have an <strong>XmlSerializer</strong> doing the
work to serialize that to the proper POX wire format.  So far, so good. 
Now, I want to retrieve that same entity back from SSDS. The key line here is the
table.Query&lt;T&gt;() call.  It accepts a <strong>Expression&lt;Func&lt;SsdsEntity&lt;T&gt;,
bool&gt;&gt;</strong> argument that represents a strongly typed query.
</p>
        <p>
For the uninitiated, the <strong>Expression&lt;TDelegate&gt;</strong> is a way to
represent lambda expressions in an abstract syntax tree.  We can think of them
as a way to model what the expression does without generating the bits of code necessary
to actually do it.  We can inspect the <strong>Expression</strong> and create
new ones based on it until finally we can call Compile and actually convert the representation
of the lambda into something that can execute.
</p>
        <p>
The <strong>Func&lt;SsdsEntity&lt;T&gt;, bool&gt;</strong> represents a delegate that
accepts a <strong>SsdsEntity&lt;T&gt;</strong> as an argument and returns a boolean. 
This effectively represents the WHERE clause in the SSDS LINQ query syntax. 
Since <strong>SsdsEntity&lt;T&gt;</strong> contains an actual type T in the <strong>Entity</strong> property,
you can query directly against it in a strongly typed fashion!
</p>
        <p>
What about those flexible properties that I added to support flexible attributes outside
of our T?  I mentioned that I wanted to keep the <strong>PropertyBucket</strong> (a <strong>Dictionary&lt;string,
object&gt;</strong>) property public for querying.  In order to use the flexible
properties that you add, you simply use it in a weakly typed manner:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">var results = container.Query&lt;Foo&gt;(e =&gt; e.PropertyBucket[<span style="color: #006080">"MyFlexProp"</span>]
&gt; 10);</pre>
        </div>
        <p>
As you can see, any boolean expression that you can think of in the string-based SSDS
LINQ query syntax can now be expressed in a strongly-typed manner using the <strong>Func&lt;SsdsEntity&lt;T&gt;,
bool&gt;</strong> lambda syntax.
</p>
        <h3>How it works
</h3>
        <p>
Since I have the expression tree of what your query looks like in strongly-typed terms,
it is a simple matter to take that and convert it to the SSDS LINQ query syntax that
looks like "from e in entities where [....] select e" that is appended to the query
string in the REST interface.  I should say it is a simple matter because <a href="http://blogs.msdn.com/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx">Matt
Warren</a> did a lot of the heavy lifting for us and provided the abstract expression
visitor (<strong>ExpressionVisitor</strong>) as well as the expression visitor that
partially evaluates the tree to evaluate constants (<strong>SubTreeEvaluator</strong>). 
This last part is important because it allows us to write this:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">int</span> i
= 10; <span style="color: #0000ff">string</span> name = <span style="color: #006080">"MyFoo"</span>;
var results = container.Query&lt;Foo&gt;(e =&gt; e.Entity.Name == name &amp;&amp;
e.Entity.Size &gt; i);</pre>
        </div>
        <p>
Without the partial tree evaluation, you would not be able to express the right hand
side of the equation.  All I had to do was implement an expression visitor that
correctly evaluated the lambda expression and converted it to the LINQ syntax that
SSDS expects (<strong>SsdsExpressionVisitor</strong>).  It would be a trivial
matter to actually implement the <strong>IQueryProvider</strong> and <strong>IQueryable</strong> interfaces
to make the whole thing work inside LINQ to Objects.
</p>
        <p>
Originally, I did supply the <strong>IQueryProvider</strong> for this implementation
but after consideration I have decided that using methods from the <strong>SsdsContainer</strong> class
instead of the standard LINQ syntax is the best way to proceed.  Mainly, this
has to do with the fact that I want to make it more explicit to the developer what
will happen under the covers rather than using the standard <strong>Where()</strong> extension
method.
</p>
        <h3>Querying data
</h3>
        <p>
The main interaction to return data is via the <strong>Query&lt;T&gt;</strong> method. 
This method is smart enough to add the Kind into the query for you based on the T
supplied.  So, if you write something like:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">var results = container.Query&lt;Foo&gt;(e =&gt; e.Entity.Size &gt; 2);</pre>
        </div>
        <p>
This is actually translated to "<em>from e in entities where e["Size"] &gt; 2 &amp;&amp;
e.Kind == "Foo" select e</em>".  The addition of the kind is important because
we want to limit the results as much as possible.  If there happened to be many
kinds in the container that had the flexible property "Size", it would actually return
those as well in the wire response.
</p>
        <p>
Of course, what about if you want that to happen?  What if you want to return
other kinds that have the "Size" property?  To do this, I have introduced a class
called <strong>SsdsEntityBucket</strong>.  It is exactly what it sounds like. 
To use it, you simply specify a query that uses additional types with either the <strong>Query&lt;T,U,V&gt;</strong> or <strong>Query&lt;T,U&gt;</strong> methods. 
Here is an example:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">var foo = <span style="color: #0000ff">new</span> Foo
{ IsPublic = <span style="color: #0000ff">true</span>, MyCheese = <span style="color: #0000ff">new</span> Cheese
{ LastModified = DateTime.Now, Name = <span style="color: #006080">"MyCheese"</span> },
Name = <span style="color: #006080">"FooMaster"</span>, Size = 10 }; container.Insert(foo,
foo.Name); container.Insert(foo.MyCheese, foo.MyCheese.Name); <span style="color: #008000">//query
for bucket...</span> var bucket = container.Query&lt;Foo, Cheese&gt;( (f, c) =&gt;
f.Entity.Name == <span style="color: #006080">"FooMaster"</span> || c.Entity.Name
== <span style="color: #006080">"MyCheese"</span> ); var f1 = bucket.GetEntities&lt;Foo&gt;().Single();
var c1 = bucket.GetEntities&lt;Cheese&gt;().Single();</pre>
        </div>
        <p>
The calls to <strong>GetEntities&lt;T&gt;</strong> returns <strong>IEnumerable&lt;SsdsEntity&lt;T&gt;&gt;</strong> again. 
However, this was done in a single call to SSDS instead of multiple calls per T.
</p>
        <h3>Paging
</h3>
        <p>
As I mentioned earlier, I wanted the developer to understand what they were doing
when they called each method, so I decided to make paging explicit.  If I had
potentially millions of entities in SSDS, it would be a bad mistake to allow a developer
to issue a simple query that seamlessly paged the items back - especially if the query
was something like <em>e =&gt; e.Id != ""</em>.  Here is how I handled paging:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">var container = ctx.OpenContainer(<span style="color: #006080">"paging"</span>);
List&lt;Foo&gt; items = <span style="color: #0000ff">new</span> List&lt;Foo&gt;(); <span style="color: #0000ff">int</span> i
= 1; container.PagedQuery&lt;Foo&gt;( e =&gt; e.Entity.Size != 0, c =&gt; { Console.WriteLine(<span style="color: #006080">"Got
Page {0}"</span>, i++); items.AddRange(c.Select(s =&gt; s.Entity)); } ); Console.WriteLine(items.Count);</pre>
        </div>
        <p>
The <strong>PagedQuery&lt;T&gt;</strong> method takes two arguments.  One is
the standard <strong>Expression&lt;Func&lt;SsdsEntity&lt;T&gt;, bool&gt;&gt;</strong> that
you use to specify the WHERE clause for SSDS, and the other is <strong>Action&lt;IEnumerable&lt;SsdsEntity&lt;T&gt;&gt;&gt;</strong> which
represents a delegate that takes an <strong>IEnumerable&lt;SsdsEntity&lt;T&gt;&gt;</strong> and
has a void return.  This is a delegate you provide that does something with the
500 entities returned per page (it gets called once per page).  Here, I am just
adding them into a <strong>List&lt;T&gt;</strong>, but I could easily be doing anything
else here.  Under the covers, this is adding the paging term dynamically into
the expression tree that is evaluated.
</p>
        <h3>What's next
</h3>
        <p>
This is a good head start on using the REST API with SSDS today.  However, there
are a number of optimizations that could be made to the model: additional overloads,
perhaps some extension methods for common operations, etc. 
</p>
        <p>
As new features are added, I will endeavor to update this as well (blob support comes
to mind here).  Additionally, I have a few optimizations planned around concurrency
for CRUD operations.  
</p>
        <p>
I have published this out to Code Gallery and I welcome feedback and bug fixes.  <a href="http://code.msdn.microsoft.com/ssdsrest">Linked
here</a>.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=b37072b9-1fe8-4785-9df3-00861ab346f7" />
      </body>
      <title>Working with Objects in SSDS Part 3</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,b37072b9-1fe8-4785-9df3-00861ab346f7.aspx</guid>
      <link>http://dunnry.com/blog/2008/07/02/WorkingWithObjectsInSSDSPart3.aspx</link>
      <pubDate>Wed, 02 Jul 2008 23:43:26 GMT</pubDate>
      <description>&lt;p&gt;
Here is my last installment in this series of working with objects in SQL Server Data
Services.&amp;nbsp; For background, readers should read the following:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://dunnry.com/blog/SerializationInSSDS.aspx"&gt;Serialization in SSDS&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://dunnry.com/blog/WorkingWithObjectsInSSDSPart1.aspx"&gt;Working with Objects
in SSDS Part 1&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://dunnry.com/blog/WorkingWithObjectsInSSDSPart2.aspx"&gt;Working with Objects
in SSDS Part 2&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Last time, we concluded with a class called &lt;strong&gt;SsdsEntity&amp;lt;T&amp;gt;&lt;/strong&gt; that
became an all-purpose wrapper or veneer around our CLR objects.&amp;nbsp; This made it
simple to take our existing classes and serialize them as entities in SSDS.
&lt;/p&gt;
&lt;p&gt;
In this post, I want to discuss how the querying in the REST library works.&amp;nbsp;
First a simple example:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;var ctx = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SsdsContext( &lt;span style="color: #006080"&gt;"authority=http://dunnry.data.beta.mssds.com/v1/;username=dunnry;password=secret"&lt;/span&gt; );
var container = ctx.OpenContainer(&lt;span style="color: #006080"&gt;"foo"&lt;/span&gt;); var
foo = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Foo { IsPublic = &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;,
Name = &lt;span style="color: #006080"&gt;"MyFoo"&lt;/span&gt;, Size = 12 }; &lt;span style="color: #008000"&gt;//insert
it with unique id guid string&lt;/span&gt; container.Insert(foo, Guid.NewGuid().ToString()); &lt;span style="color: #008000"&gt;//now
query for it&lt;/span&gt; var results = container.Query&amp;lt;Foo&amp;gt;(e =&amp;gt; e.Entity.IsPublic
== &lt;span style="color: #0000ff"&gt;false&lt;/span&gt; &amp;amp;&amp;amp; e.Entity.Size &amp;gt; 2); &lt;span style="color: #008000"&gt;//Query&amp;lt;T&amp;gt;
returns IEnumerable&amp;lt;SsdsEntity&amp;lt;T&amp;gt;&amp;gt;, so foreach over it&lt;/span&gt; &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var
item &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; results) { Console.WriteLine(item.Entity.Name);
}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
I glossed over it in my previous posts with this library, but I have a class called &lt;strong&gt;SsdsContext&lt;/strong&gt; that
acts as my credential store and factory to create &lt;strong&gt;SsdsContainer&lt;/strong&gt; objects
where I perform my operations.&amp;nbsp; Here, I have opened a container called 'foo',
which would relate to the URI (&lt;a href="http://dunnry.data.beta.mssds.com/v1/foo"&gt;http://dunnry.data.beta.mssds.com/v1/foo&lt;/a&gt;)
according to the authority name I passed on the &lt;strong&gt;SsdsContext&lt;/strong&gt; constructor
arguments.
&lt;/p&gt;
&lt;p&gt;
I created an instance of my &lt;strong&gt;Foo&lt;/strong&gt; class (see &lt;a href="http://dunnry.com/blog/WorkingWithObjectsInSSDSPart1.aspx"&gt;this
post&lt;/a&gt; if you want to see what a &lt;strong&gt;Foo&lt;/strong&gt; looks like) and inserted it.&amp;nbsp;
We know that under the covers we have an &lt;strong&gt;XmlSerializer&lt;/strong&gt; doing the
work to serialize that to the proper POX wire format.&amp;nbsp; So far, so good.&amp;nbsp;
Now, I want to retrieve that same entity back from SSDS. The key line here is the
table.Query&amp;lt;T&amp;gt;() call.&amp;nbsp; It accepts a &lt;strong&gt;Expression&amp;lt;Func&amp;lt;SsdsEntity&amp;lt;T&amp;gt;,
bool&amp;gt;&amp;gt;&lt;/strong&gt; argument that represents a strongly typed query.
&lt;/p&gt;
&lt;p&gt;
For the uninitiated, the &lt;strong&gt;Expression&amp;lt;TDelegate&amp;gt;&lt;/strong&gt; is a way to
represent lambda expressions in an abstract syntax tree.&amp;nbsp; We can think of them
as a way to model what the expression does without generating the bits of code necessary
to actually do it.&amp;nbsp; We can inspect the &lt;strong&gt;Expression&lt;/strong&gt; and create
new ones based on it until finally we can call Compile and actually convert the representation
of the lambda into something that can execute.
&lt;/p&gt;
&lt;p&gt;
The &lt;strong&gt;Func&amp;lt;SsdsEntity&amp;lt;T&amp;gt;, bool&amp;gt;&lt;/strong&gt; represents a delegate that
accepts a &lt;strong&gt;SsdsEntity&amp;lt;T&amp;gt;&lt;/strong&gt; as an argument and returns a boolean.&amp;nbsp;
This effectively represents the WHERE clause in the SSDS LINQ query syntax.&amp;nbsp;
Since &lt;strong&gt;SsdsEntity&amp;lt;T&amp;gt;&lt;/strong&gt; contains an actual type T in the &lt;strong&gt;Entity&lt;/strong&gt; property,
you can query directly against it in a strongly typed fashion!
&lt;/p&gt;
&lt;p&gt;
What about those flexible properties that I added to support flexible attributes outside
of our T?&amp;nbsp; I mentioned that I wanted to keep the &lt;strong&gt;PropertyBucket&lt;/strong&gt; (a &lt;strong&gt;Dictionary&amp;lt;string,
object&amp;gt;&lt;/strong&gt;) property public for querying.&amp;nbsp; In order to use the flexible
properties that you add, you simply use it in a weakly typed manner:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;var results = container.Query&amp;lt;Foo&amp;gt;(e =&amp;gt; e.PropertyBucket[&lt;span style="color: #006080"&gt;"MyFlexProp"&lt;/span&gt;]
&amp;gt; 10);&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
As you can see, any boolean expression that you can think of in the string-based SSDS
LINQ query syntax can now be expressed in a strongly-typed manner using the &lt;strong&gt;Func&amp;lt;SsdsEntity&amp;lt;T&amp;gt;,
bool&amp;gt;&lt;/strong&gt; lambda syntax.
&lt;/p&gt;
&lt;h3&gt;How it works
&lt;/h3&gt;
&lt;p&gt;
Since I have the expression tree of what your query looks like in strongly-typed terms,
it is a simple matter to take that and convert it to the SSDS LINQ query syntax that
looks like "from e in entities where [....] select e" that is appended to the query
string in the REST interface.&amp;nbsp; I should say it is a simple matter because &lt;a href="http://blogs.msdn.com/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx"&gt;Matt
Warren&lt;/a&gt; did a lot of the heavy lifting for us and provided the abstract expression
visitor (&lt;strong&gt;ExpressionVisitor&lt;/strong&gt;) as well as the expression visitor that
partially evaluates the tree to evaluate constants (&lt;strong&gt;SubTreeEvaluator&lt;/strong&gt;).&amp;nbsp;
This last part is important because it allows us to write this:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i
= 10; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; name = &lt;span style="color: #006080"&gt;"MyFoo"&lt;/span&gt;;
var results = container.Query&amp;lt;Foo&amp;gt;(e =&amp;gt; e.Entity.Name == name &amp;amp;&amp;amp;
e.Entity.Size &amp;gt; i);&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Without the partial tree evaluation, you would not be able to express the right hand
side of the equation.&amp;nbsp; All I had to do was implement an expression visitor that
correctly evaluated the lambda expression and converted it to the LINQ syntax that
SSDS expects (&lt;strong&gt;SsdsExpressionVisitor&lt;/strong&gt;).&amp;nbsp; It would be a trivial
matter to actually implement the &lt;strong&gt;IQueryProvider&lt;/strong&gt; and &lt;strong&gt;IQueryable&lt;/strong&gt; interfaces
to make the whole thing work inside LINQ to Objects.
&lt;/p&gt;
&lt;p&gt;
Originally, I did supply the &lt;strong&gt;IQueryProvider&lt;/strong&gt; for this implementation
but after consideration I have decided that using methods from the &lt;strong&gt;SsdsContainer&lt;/strong&gt; class
instead of the standard LINQ syntax is the best way to proceed.&amp;nbsp; Mainly, this
has to do with the fact that I want to make it more explicit to the developer what
will happen under the covers rather than using the standard &lt;strong&gt;Where()&lt;/strong&gt; extension
method.
&lt;/p&gt;
&lt;h3&gt;Querying data
&lt;/h3&gt;
&lt;p&gt;
The main interaction to return data is via the &lt;strong&gt;Query&amp;lt;T&amp;gt;&lt;/strong&gt; method.&amp;nbsp;
This method is smart enough to add the Kind into the query for you based on the T
supplied.&amp;nbsp; So, if you write something like:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;var results = container.Query&amp;lt;Foo&amp;gt;(e =&amp;gt; e.Entity.Size &amp;gt; 2);&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
This is actually translated to "&lt;em&gt;from e in entities where e["Size"] &amp;gt; 2 &amp;amp;&amp;amp;
e.Kind == "Foo" select e&lt;/em&gt;".&amp;nbsp; The addition of the kind is important because
we want to limit the results as much as possible.&amp;nbsp; If there happened to be many
kinds in the container that had the flexible property "Size", it would actually return
those as well in the wire response.
&lt;/p&gt;
&lt;p&gt;
Of course, what about if you want that to happen?&amp;nbsp; What if you want to return
other kinds that have the "Size" property?&amp;nbsp; To do this, I have introduced a class
called &lt;strong&gt;SsdsEntityBucket&lt;/strong&gt;.&amp;nbsp; It is exactly what it sounds like.&amp;nbsp;
To use it, you simply specify a query that uses additional types with either the &lt;strong&gt;Query&amp;lt;T,U,V&amp;gt;&lt;/strong&gt; or &lt;strong&gt;Query&amp;lt;T,U&amp;gt;&lt;/strong&gt; methods.&amp;nbsp;
Here is an example:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;var foo = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Foo
{ IsPublic = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;, MyCheese = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Cheese
{ LastModified = DateTime.Now, Name = &lt;span style="color: #006080"&gt;"MyCheese"&lt;/span&gt; },
Name = &lt;span style="color: #006080"&gt;"FooMaster"&lt;/span&gt;, Size = 10 }; container.Insert(foo,
foo.Name); container.Insert(foo.MyCheese, foo.MyCheese.Name); &lt;span style="color: #008000"&gt;//query
for bucket...&lt;/span&gt; var bucket = container.Query&amp;lt;Foo, Cheese&amp;gt;( (f, c) =&amp;gt;
f.Entity.Name == &lt;span style="color: #006080"&gt;"FooMaster"&lt;/span&gt; || c.Entity.Name
== &lt;span style="color: #006080"&gt;"MyCheese"&lt;/span&gt; ); var f1 = bucket.GetEntities&amp;lt;Foo&amp;gt;().Single();
var c1 = bucket.GetEntities&amp;lt;Cheese&amp;gt;().Single();&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
The calls to &lt;strong&gt;GetEntities&amp;lt;T&amp;gt;&lt;/strong&gt; returns &lt;strong&gt;IEnumerable&amp;lt;SsdsEntity&amp;lt;T&amp;gt;&amp;gt;&lt;/strong&gt; again.&amp;nbsp;
However, this was done in a single call to SSDS instead of multiple calls per T.
&lt;/p&gt;
&lt;h3&gt;Paging
&lt;/h3&gt;
&lt;p&gt;
As I mentioned earlier, I wanted the developer to understand what they were doing
when they called each method, so I decided to make paging explicit.&amp;nbsp; If I had
potentially millions of entities in SSDS, it would be a bad mistake to allow a developer
to issue a simple query that seamlessly paged the items back - especially if the query
was something like &lt;em&gt;e =&amp;gt; e.Id != ""&lt;/em&gt;.&amp;nbsp; Here is how I handled paging:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;var container = ctx.OpenContainer(&lt;span style="color: #006080"&gt;"paging"&lt;/span&gt;);
List&amp;lt;Foo&amp;gt; items = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;Foo&amp;gt;(); &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i
= 1; container.PagedQuery&amp;lt;Foo&amp;gt;( e =&amp;gt; e.Entity.Size != 0, c =&amp;gt; { Console.WriteLine(&lt;span style="color: #006080"&gt;"Got
Page {0}"&lt;/span&gt;, i++); items.AddRange(c.Select(s =&amp;gt; s.Entity)); } ); Console.WriteLine(items.Count);&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
The &lt;strong&gt;PagedQuery&amp;lt;T&amp;gt;&lt;/strong&gt; method takes two arguments.&amp;nbsp; One is
the standard &lt;strong&gt;Expression&amp;lt;Func&amp;lt;SsdsEntity&amp;lt;T&amp;gt;, bool&amp;gt;&amp;gt;&lt;/strong&gt; that
you use to specify the WHERE clause for SSDS, and the other is &lt;strong&gt;Action&amp;lt;IEnumerable&amp;lt;SsdsEntity&amp;lt;T&amp;gt;&amp;gt;&amp;gt;&lt;/strong&gt; which
represents a delegate that takes an &lt;strong&gt;IEnumerable&amp;lt;SsdsEntity&amp;lt;T&amp;gt;&amp;gt;&lt;/strong&gt; and
has a void return.&amp;nbsp; This is a delegate you provide that does something with the
500 entities returned per page (it gets called once per page).&amp;nbsp; Here, I am just
adding them into a &lt;strong&gt;List&amp;lt;T&amp;gt;&lt;/strong&gt;, but I could easily be doing anything
else here.&amp;nbsp; Under the covers, this is adding the paging term dynamically into
the expression tree that is evaluated.
&lt;/p&gt;
&lt;h3&gt;What's next
&lt;/h3&gt;
&lt;p&gt;
This is a good head start on using the REST API with SSDS today.&amp;nbsp; However, there
are a number of optimizations that could be made to the model: additional overloads,
perhaps some extension methods for common operations, etc. 
&lt;/p&gt;
&lt;p&gt;
As new features are added, I will endeavor to update this as well (blob support comes
to mind here).&amp;nbsp; Additionally, I have a few optimizations planned around concurrency
for CRUD operations.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
I have published this out to Code Gallery and I welcome feedback and bug fixes.&amp;nbsp; &lt;a href="http://code.msdn.microsoft.com/ssdsrest"&gt;Linked
here&lt;/a&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=b37072b9-1fe8-4785-9df3-00861ab346f7" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,b37072b9-1fe8-4785-9df3-00861ab346f7.aspx</comments>
      <category>.NET</category>
      <category>Cloud Services</category>
      <category>SSDS</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=bdbc0cbd-e845-49e9-9e43-52a079bda687</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,bdbc0cbd-e845-49e9-9e43-52a079bda687.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,bdbc0cbd-e845-49e9-9e43-52a079bda687.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=bdbc0cbd-e845-49e9-9e43-52a079bda687</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This is the second post in my series on working with SQL Server Data Service (SSDS)
and objects.  For background, you should read my post on <a href="http://dunnry.com/blog/SerializationInSSDS.aspx">Serializing
Objects in SSDS</a> and the <a href="http://dunnry.com/blog/WorkingWithObjectsInSSDSPart1.aspx">first
post</a> in this series.
</p>
        <p>
Last time I showed how to create a general purpose serializer for SSDS using the standard <strong>XmlSerializer</strong> class
in .NET.  I created a shell entity or a 'thin veneer' for objects called <strong>SsdsEntity&lt;T&gt;</strong>,
where T was any POCO (plain old C#/CLR object).  This allowed me to abstract
away the metadata properties required for SSDS without changing my actual POCO object
(which, I noted was lame to do).
</p>
        <p>
If we decide that we will use SSDS to interact with POCO T, an interesting situation
arises.  Namely, once we have defined T, we have in fact defined a schema - albeit
one only enforced in code you write and not by the SSDS service itself.  One
of the advantages of using something like SSDS is that you have a lot of flexibility
in storing entities  (hence the term 'flexible entity') without conforming to
schema.  Since, I want to support this flexibility, it means I need to think
of a way to support not only the schema implied by T, but also additional and arbitrary
properties that a user might consider.
</p>
        <p>
Some may wonder why we need this flexibility:  after all, why not just change
T to support whatever we like?  The issue comes up most often with code you do
not control.  If you already have an existing codebase with objects that you
would like to store in SSDS, it might not be practical or even possible to change
the T to add additional schema.
</p>
        <p>
Even if you completely control the codebase, expressing relationships between CLR
objects and expressing relationships between things in your data are two different
ideas - sometimes this problem has been termed 'impedance mismatch'.
</p>
        <p>
In the CLR, if two objects are related, they are often part of a collection, or they
refer to an instance on another object.  This is easy to express in the CLR (e.g. <strong>Instance.ChildrenCollection["key"]</strong>). 
In your typical datasource, this same relationship is done using foreign keys to refer
to other entities.
</p>
        <p>
Consider the following classes:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">public</span>
            <span style="color: #0000ff">class</span> Employee
{ <span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> EmployeeId
{ get; set; } <span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> Name
{ get; set; } <span style="color: #0000ff">public</span> DateTime HireDate { get;
set; } <span style="color: #0000ff">public</span> Employee Manager { get; set; } <span style="color: #0000ff">public</span> Project[]
Projects { get; set; } } <span style="color: #0000ff">public</span><span style="color: #0000ff">class</span> Project
{ <span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> ProjectId
{ get; set; } <span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> Name
{ get; set; } <span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> BillCode
{ get; set; } }</pre>
        </div>
        <p>
Here we see that the <strong>Employee</strong> class refers to itself as well as contains
a collection of related projects (<strong>Project</strong> class) that the employee
works on.  SSDS only supports simple scalar types and no arrays or nested objects
today, so we cannot directly express this in SSDS.  However, we can decompose
this class and store the bits separately and then reassemble later.  First, let's
see what that looks like and then we can see how it was done:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">var projects = <span style="color: #0000ff">new</span> Project[]
{ <span style="color: #0000ff">new</span> Project { BillCode = <span style="color: #006080">"123"</span>,
Name = <span style="color: #006080">"TPS Slave"</span>, ProjectId = <span style="color: #006080">"PID01"</span>}, <span style="color: #0000ff">new</span> Project
{ BillCode = <span style="color: #006080">"124"</span>, Name = <span style="color: #006080">"Programmer"</span>,
ProjectId = <span style="color: #006080">"PID02"</span> } }; var bill = <span style="color: #0000ff">new</span> Employee
{ EmployeeId = <span style="color: #006080">"EMP01"</span>, HireDate = DateTime.Now.AddMonths(-1),
Manager = <span style="color: #0000ff">null</span>, Name = <span style="color: #006080">"Bill
Lumbergh"</span>, Projects = <span style="color: #0000ff">new</span> Project[] {}
}; var peter = <span style="color: #0000ff">new</span> Employee { EmployeeId = <span style="color: #006080">"EMP02"</span>,
HireDate = DateTime.Now, Manager = bill, Name = <span style="color: #006080">"Peter
Gibbons"</span>, Projects = projects }; var cloudpeter = <span style="color: #0000ff">new</span> SsdsEntity&lt;Employee&gt;
{ Entity = peter, Id = peter.EmployeeId }; var cloudbill = <span style="color: #0000ff">new</span> SsdsEntity&lt;Employee&gt;
{ Entity = bill, Id = bill.EmployeeId }; <span style="color: #008000">//here is how
we add flexible props</span> cloudpeter.Add&lt;<span style="color: #0000ff">string</span>&gt;(<span style="color: #006080">"ManagerId"</span>,
peter.Manager.EmployeeId); var table = _context.OpenContainer(<span style="color: #006080">"initech"</span>);
table.Insert(cloudpeter); table.Insert(cloudbill); var cloudprojects = peter.Projects
.Select(s =&gt; <span style="color: #0000ff">new</span> SsdsEntity&lt;Project&gt;
{ Entity = s, Id = Guid.NewGuid().ToString() }); <span style="color: #008000">//add
some metadata to track the project to employee</span><span style="color: #0000ff">foreach</span> (var
proj <span style="color: #0000ff">in</span> cloudprojects) { proj.Add&lt;<span style="color: #0000ff">string</span>&gt;(<span style="color: #006080">"RelatedEmployee"</span>,
peter.EmployeeId); table.Insert(proj); }</pre>
        </div>
        <p>
All this code does is create two employees and two projects and set the relationships
between them.  Using the <strong>Add&lt;K&gt;</strong> method, I can insert any
primitive type to go along for the ride with the POCO.  If we query the container
now, this is what we see:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">&lt;</span>
            <span style="color: #800000">s:EntitySet</span>
            <span style="color: #ff0000">xmlns:s</span>
            <span style="color: #0000ff">="http://schemas.microsoft.com/sitka/2008/03/"</span>
            <span style="color: #ff0000">xmlns:xsi</span>
            <span style="color: #0000ff">="http://www.w3.org/2001/XMLSchema-instance"</span>
            <span style="color: #ff0000">xmlns:x</span>
            <span style="color: #0000ff">="http://www.w3.org/2001/XMLSchema"</span>
            <span style="color: #0000ff">&gt;</span>
            <span style="color: #0000ff">&lt;</span>
            <span style="color: #800000">Project</span>
            <span style="color: #0000ff">&gt;</span>
            <span style="color: #0000ff">&lt;</span>
            <span style="color: #800000">s:Id</span>
            <span style="color: #0000ff">&gt;</span>2ffd7a92-2a3b-4cd8-a5f7-55f40c3ba2b0<span style="color: #0000ff">&lt;/</span><span style="color: #800000">s:Id</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">s:Version</span><span style="color: #0000ff">&gt;</span>1<span style="color: #0000ff">&lt;/</span><span style="color: #800000">s:Version</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">ProjectId</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:string"</span><span style="color: #0000ff">&gt;</span>PID01<span style="color: #0000ff">&lt;/</span><span style="color: #800000">ProjectId</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">Name</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:string"</span><span style="color: #0000ff">&gt;</span>TPS
Slave<span style="color: #0000ff">&lt;/</span><span style="color: #800000">Name</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">BillCode</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:string"</span><span style="color: #0000ff">&gt;</span>123<span style="color: #0000ff">&lt;/</span><span style="color: #800000">BillCode</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">RelatedEmployee</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:string"</span><span style="color: #0000ff">&gt;</span>EMP02<span style="color: #0000ff">&lt;/</span><span style="color: #800000">RelatedEmployee</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">Project</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">Project</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">s:Id</span><span style="color: #0000ff">&gt;</span>892dbb1e-ba47-4c87-80e6-64fbb46da935<span style="color: #0000ff">&lt;/</span><span style="color: #800000">s:Id</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">s:Version</span><span style="color: #0000ff">&gt;</span>1<span style="color: #0000ff">&lt;/</span><span style="color: #800000">s:Version</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">ProjectId</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:string"</span><span style="color: #0000ff">&gt;</span>PID02<span style="color: #0000ff">&lt;/</span><span style="color: #800000">ProjectId</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">Name</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:string"</span><span style="color: #0000ff">&gt;</span>Programmer<span style="color: #0000ff">&lt;/</span><span style="color: #800000">Name</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">BillCode</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:string"</span><span style="color: #0000ff">&gt;</span>124<span style="color: #0000ff">&lt;/</span><span style="color: #800000">BillCode</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">RelatedEmployee</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:string"</span><span style="color: #0000ff">&gt;</span>EMP02<span style="color: #0000ff">&lt;/</span><span style="color: #800000">RelatedEmployee</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">Project</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">Employee</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">s:Id</span><span style="color: #0000ff">&gt;</span>EMP01<span style="color: #0000ff">&lt;/</span><span style="color: #800000">s:Id</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">s:Version</span><span style="color: #0000ff">&gt;</span>1<span style="color: #0000ff">&lt;/</span><span style="color: #800000">s:Version</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">EmployeeId</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:string"</span><span style="color: #0000ff">&gt;</span>EMP01<span style="color: #0000ff">&lt;/</span><span style="color: #800000">EmployeeId</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">Name</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:string"</span><span style="color: #0000ff">&gt;</span>Bill
Lumbergh<span style="color: #0000ff">&lt;/</span><span style="color: #800000">Name</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">HireDate</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:dateTime"</span><span style="color: #0000ff">&gt;</span>2008-05-25T23:59:49<span style="color: #0000ff">&lt;/</span><span style="color: #800000">HireDate</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">Employee</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">Employee</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">s:Id</span><span style="color: #0000ff">&gt;</span>EMP02<span style="color: #0000ff">&lt;/</span><span style="color: #800000">s:Id</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">s:Version</span><span style="color: #0000ff">&gt;</span>1<span style="color: #0000ff">&lt;/</span><span style="color: #800000">s:Version</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">EmployeeId</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:string"</span><span style="color: #0000ff">&gt;</span>EMP02<span style="color: #0000ff">&lt;/</span><span style="color: #800000">EmployeeId</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">Name</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:string"</span><span style="color: #0000ff">&gt;</span>Peter
Gibbons<span style="color: #0000ff">&lt;/</span><span style="color: #800000">Name</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">HireDate</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:dateTime"</span><span style="color: #0000ff">&gt;</span>2008-06-25T23:59:49<span style="color: #0000ff">&lt;/</span><span style="color: #800000">HireDate</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">ManagerId</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:string"</span><span style="color: #0000ff">&gt;</span>EMP01<span style="color: #0000ff">&lt;/</span><span style="color: #800000">ManagerId</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">Employee</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">s:EntitySet</span><span style="color: #0000ff">&gt;</span></pre>
        </div>
        <p>
As you can see, I have stored extra data in my 'flexible' entity with the <strong>ManagerId</strong> property
(on one entity) and <strong>RelatedEmployee</strong> property on the <strong>Project</strong> kinds. 
This allows me to figure out later what objects are related to each other since we
can't model the CLR objects relationships directly.  Let's see how this was done.
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">public</span>
            <span style="color: #0000ff">class</span> SsdsEntity&lt;T&gt; <span style="color: #0000ff">where</span> T: <span style="color: #0000ff">class</span> {
Dictionary&lt;<span style="color: #0000ff">string</span>, <span style="color: #0000ff">object</span>&gt;
_propertyBucket = <span style="color: #0000ff">new</span> Dictionary&lt;<span style="color: #0000ff">string</span>, <span style="color: #0000ff">object</span>&gt;(); <span style="color: #0000ff">public</span> SsdsEntity()
{ } [XmlIgnore] <span style="color: #0000ff">public</span> Dictionary&lt;<span style="color: #0000ff">string</span>, <span style="color: #0000ff">object</span>&gt;
PropertyBucket { get { <span style="color: #0000ff">return</span> _propertyBucket;
} } [XmlAnyElement] <span style="color: #0000ff">public</span> XElement[] Attributes
{ get { <span style="color: #008000">//using XElement is much easier than XmlElement
to build</span><span style="color: #008000">//take all properties on object instance
and build XElement</span> var props = from prop <span style="color: #0000ff">in</span><span style="color: #0000ff">typeof</span>(T).GetProperties()
let val = prop.GetValue(<span style="color: #0000ff">this</span>.Entity, <span style="color: #0000ff">null</span>) <span style="color: #0000ff">where</span> prop.GetSetMethod()
!= <span style="color: #0000ff">null</span> &amp;&amp; allowableTypes.Contains(prop.PropertyType)
&amp;&amp; val != <span style="color: #0000ff">null</span> select <span style="color: #0000ff">new</span> XElement(prop.Name, <span style="color: #0000ff">new</span> XAttribute(Constants.xsi
+ <span style="color: #006080">"type"</span>, XsdTypeResolver.Solve(prop.PropertyType)),
EncodeValue(val) ); <span style="color: #008000">//Then stuff in any extra stuff you
want</span> var extra = _propertyBucket.Select( e =&gt; <span style="color: #0000ff">new</span> XElement(e.Key, <span style="color: #0000ff">new</span> XAttribute(Constants.xsi
+ <span style="color: #006080">"type"</span>, XsdTypeResolver.Solve(e.Value.GetType())),
EncodeValue(e.Value) ) ); <span style="color: #0000ff">return</span> props.Union(extra).ToArray();
} set { <span style="color: #008000">//wrap the XElement[] with the name of the type</span> var
xml = <span style="color: #0000ff">new</span> XElement(<span style="color: #0000ff">typeof</span>(T).Name, <span style="color: #0000ff">value</span>);
var xs = <span style="color: #0000ff">new</span> XmlSerializer(<span style="color: #0000ff">typeof</span>(T)); <span style="color: #008000">//xml.CreateReader()
cannot be used as it won't support base64 content</span> XmlTextReader reader = <span style="color: #0000ff">new</span> XmlTextReader(
xml.ToString(), XmlNodeType.Document, <span style="color: #0000ff">null</span> ); <span style="color: #0000ff">this</span>.Entity
= (T)xs.Deserialize(reader); <span style="color: #008000">//now deserialize the other
stuff left over into the property bucket...</span> var stuff = from v <span style="color: #0000ff">in</span><span style="color: #0000ff">value</span>.AsEnumerable()
let props = <span style="color: #0000ff">typeof</span>(T).GetProperties().Select(s
=&gt; s.Name) <span style="color: #0000ff">where</span> !props.Contains(v.Name.ToString())
select v; <span style="color: #0000ff">foreach</span> (var item <span style="color: #0000ff">in</span> stuff)
{ _propertyBucket.Add( item.Name.ToString(), DecodeValue( item.Attribute(Constants.xsi
+ <span style="color: #006080">"type"</span>).Value, item.Value) ); } } } <span style="color: #0000ff">public</span><span style="color: #0000ff">void</span> Add&lt;K&gt;(<span style="color: #0000ff">string</span> key,
K <span style="color: #0000ff">value</span>) { <span style="color: #0000ff">if</span> (!allowableTypes.Contains(<span style="color: #0000ff">typeof</span>(K))) <span style="color: #0000ff">throw</span><span style="color: #0000ff">new</span> ArgumentException(
String.Format( <span style="color: #006080">"Type {0} not supported in SsdsEntity"</span>, <span style="color: #0000ff">typeof</span>(K).Name)
); <span style="color: #0000ff">if</span> (!_propertyBucket.ContainsKey(key)) { _propertyBucket.Add(key, <span style="color: #0000ff">value</span>);
} <span style="color: #0000ff">else</span> { <span style="color: #008000">//replace
the value</span> _propertyBucket.Remove(key); _propertyBucket.Add(key, <span style="color: #0000ff">value</span>);
} } }</pre>
        </div>
        <p>
I have omitted the parts of <strong>SsdsEntity&lt;T&gt;</strong> from the first post
that didn't change.  The only other addition you don't see here is a helper method
called <strong>DecodeValue</strong>, which as you might guess, interprets the string
value in XML and attempts to cast it to a CLR type based on the xsi:type that comes
back.
</p>
        <p>
All we did here was add a <strong>Dictionary&lt;string, object&gt;</strong> property
called <strong>PropertyBucket</strong> that holds our extra stuff we want to associate
with our T instance.  Then in the getter and setter for the <strong>XElement[]</strong> property
called <strong>Attributes</strong>, we are adding them into our array of <strong>XElement</strong> as
well as pulling them back out on deserialization and stuffing them back into the Dictionary. 
With this simple addition, we have fixed our in flexibility (or lack thereof) problem. 
We are still limited to the simple scalar types, but as you can see you can work around
this in a lot of cases by decomposing the objects down enough to be able to recreate
them later.
</p>
        <p>
The <strong>Add&lt;K&gt;</strong> method is a convenience only as we could operate
directly against the Dictionary.  I also could have chosen to keep the Dictionary
property bucket private and not expose it.  That would have worked just fine
for serialization, but I wanted to also be able to query it later.
</p>
        <p>
In my last post, I said I would introduce a library where all this code is coming
from, but I didn't realize at the time how long this post would be and that I still
need to cover querying.  So... next time, I will finish up this series by explaining
how the strongly typed query model works and how all these pieces fit together to
recompose the data back into objects (and release the library).
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=bdbc0cbd-e845-49e9-9e43-52a079bda687" />
      </body>
      <title>Working with Objects in SSDS Part 2</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,bdbc0cbd-e845-49e9-9e43-52a079bda687.aspx</guid>
      <link>http://dunnry.com/blog/2008/06/26/WorkingWithObjectsInSSDSPart2.aspx</link>
      <pubDate>Thu, 26 Jun 2008 20:03:54 GMT</pubDate>
      <description>&lt;p&gt;
This is the second post in my series on working with SQL Server Data Service (SSDS)
and objects.&amp;nbsp; For background, you should read my post on &lt;a href="http://dunnry.com/blog/SerializationInSSDS.aspx"&gt;Serializing
Objects in SSDS&lt;/a&gt; and the &lt;a href="http://dunnry.com/blog/WorkingWithObjectsInSSDSPart1.aspx"&gt;first
post&lt;/a&gt; in this series.
&lt;/p&gt;
&lt;p&gt;
Last time I showed how to create a general purpose serializer for SSDS using the standard &lt;strong&gt;XmlSerializer&lt;/strong&gt; class
in .NET.&amp;nbsp; I created a shell entity or a 'thin veneer' for objects called &lt;strong&gt;SsdsEntity&amp;lt;T&amp;gt;&lt;/strong&gt;,
where T was any POCO (plain old C#/CLR object).&amp;nbsp; This allowed me to abstract
away the metadata properties required for SSDS without changing my actual POCO object
(which, I noted was lame to do).
&lt;/p&gt;
&lt;p&gt;
If we decide that we will use SSDS to interact with POCO T, an interesting situation
arises.&amp;nbsp; Namely, once we have defined T, we have in fact defined a schema - albeit
one only enforced in code you write and not by the SSDS service itself.&amp;nbsp; One
of the advantages of using something like SSDS is that you have a lot of flexibility
in storing entities&amp;nbsp; (hence the term 'flexible entity') without conforming to
schema.&amp;nbsp; Since, I want to support this flexibility, it means I need to think
of a way to support not only the schema implied by T, but also additional and arbitrary
properties that a user might consider.
&lt;/p&gt;
&lt;p&gt;
Some may wonder why we need this flexibility:&amp;nbsp; after all, why not just change
T to support whatever we like?&amp;nbsp; The issue comes up most often with code you do
not control.&amp;nbsp; If you already have an existing codebase with objects that you
would like to store in SSDS, it might not be practical or even possible to change
the T to add additional schema.
&lt;/p&gt;
&lt;p&gt;
Even if you completely control the codebase, expressing relationships between CLR
objects and expressing relationships between things in your data are two different
ideas - sometimes this problem has been termed 'impedance mismatch'.
&lt;/p&gt;
&lt;p&gt;
In the CLR, if two objects are related, they are often part of a collection, or they
refer to an instance on another object.&amp;nbsp; This is easy to express in the CLR (e.g. &lt;strong&gt;Instance.ChildrenCollection["key"]&lt;/strong&gt;).&amp;nbsp;
In your typical datasource, this same relationship is done using foreign keys to refer
to other entities.
&lt;/p&gt;
&lt;p&gt;
Consider the following classes:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Employee
{ &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; EmployeeId
{ get; set; } &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Name
{ get; set; } &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; DateTime HireDate { get;
set; } &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Employee Manager { get; set; } &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Project[]
Projects { get; set; } } &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Project
{ &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ProjectId
{ get; set; } &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Name
{ get; set; } &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; BillCode
{ get; set; } }&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Here we see that the &lt;strong&gt;Employee&lt;/strong&gt; class refers to itself as well as contains
a collection of related projects (&lt;strong&gt;Project&lt;/strong&gt; class) that the employee
works on.&amp;nbsp; SSDS only supports simple scalar types and no arrays or nested objects
today, so we cannot directly express this in SSDS.&amp;nbsp; However, we can decompose
this class and store the bits separately and then reassemble later.&amp;nbsp; First, let's
see what that looks like and then we can see how it was done:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;var projects = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Project[]
{ &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Project { BillCode = &lt;span style="color: #006080"&gt;"123"&lt;/span&gt;,
Name = &lt;span style="color: #006080"&gt;"TPS Slave"&lt;/span&gt;, ProjectId = &lt;span style="color: #006080"&gt;"PID01"&lt;/span&gt;}, &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Project
{ BillCode = &lt;span style="color: #006080"&gt;"124"&lt;/span&gt;, Name = &lt;span style="color: #006080"&gt;"Programmer"&lt;/span&gt;,
ProjectId = &lt;span style="color: #006080"&gt;"PID02"&lt;/span&gt; } }; var bill = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Employee
{ EmployeeId = &lt;span style="color: #006080"&gt;"EMP01"&lt;/span&gt;, HireDate = DateTime.Now.AddMonths(-1),
Manager = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;, Name = &lt;span style="color: #006080"&gt;"Bill
Lumbergh"&lt;/span&gt;, Projects = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Project[] {}
}; var peter = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Employee { EmployeeId = &lt;span style="color: #006080"&gt;"EMP02"&lt;/span&gt;,
HireDate = DateTime.Now, Manager = bill, Name = &lt;span style="color: #006080"&gt;"Peter
Gibbons"&lt;/span&gt;, Projects = projects }; var cloudpeter = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SsdsEntity&amp;lt;Employee&amp;gt;
{ Entity = peter, Id = peter.EmployeeId }; var cloudbill = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SsdsEntity&amp;lt;Employee&amp;gt;
{ Entity = bill, Id = bill.EmployeeId }; &lt;span style="color: #008000"&gt;//here is how
we add flexible props&lt;/span&gt; cloudpeter.Add&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;&amp;gt;(&lt;span style="color: #006080"&gt;"ManagerId"&lt;/span&gt;,
peter.Manager.EmployeeId); var table = _context.OpenContainer(&lt;span style="color: #006080"&gt;"initech"&lt;/span&gt;);
table.Insert(cloudpeter); table.Insert(cloudbill); var cloudprojects = peter.Projects
.Select(s =&amp;gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SsdsEntity&amp;lt;Project&amp;gt;
{ Entity = s, Id = Guid.NewGuid().ToString() }); &lt;span style="color: #008000"&gt;//add
some metadata to track the project to employee&lt;/span&gt; &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var
proj &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; cloudprojects) { proj.Add&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;&amp;gt;(&lt;span style="color: #006080"&gt;"RelatedEmployee"&lt;/span&gt;,
peter.EmployeeId); table.Insert(proj); }&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
All this code does is create two employees and two projects and set the relationships
between them.&amp;nbsp; Using the &lt;strong&gt;Add&amp;lt;K&amp;gt;&lt;/strong&gt; method, I can insert any
primitive type to go along for the ride with the POCO.&amp;nbsp; If we query the container
now, this is what we see:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;s:EntitySet&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xmlns:s&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="http://schemas.microsoft.com/sitka/2008/03/"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xmlns:xsi&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xmlns:x&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="http://www.w3.org/2001/XMLSchema"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Project&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;2ffd7a92-2a3b-4cd8-a5f7-55f40c3ba2b0&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;1&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ProjectId&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:string"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;PID01&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;ProjectId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Name&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:string"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;TPS
Slave&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;BillCode&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:string"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;123&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;BillCode&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;RelatedEmployee&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:string"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;EMP02&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;RelatedEmployee&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Project&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Project&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;892dbb1e-ba47-4c87-80e6-64fbb46da935&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;1&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ProjectId&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:string"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;PID02&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;ProjectId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Name&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:string"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Programmer&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;BillCode&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:string"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;124&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;BillCode&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;RelatedEmployee&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:string"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;EMP02&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;RelatedEmployee&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Project&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Employee&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;EMP01&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;1&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;EmployeeId&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:string"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;EMP01&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;EmployeeId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Name&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:string"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Bill
Lumbergh&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;HireDate&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:dateTime"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;2008-05-25T23:59:49&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;HireDate&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Employee&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Employee&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;EMP02&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;1&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;EmployeeId&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:string"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;EMP02&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;EmployeeId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Name&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:string"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Peter
Gibbons&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;HireDate&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:dateTime"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;2008-06-25T23:59:49&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;HireDate&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ManagerId&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:string"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;EMP01&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;ManagerId&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Employee&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;s:EntitySet&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
As you can see, I have stored extra data in my 'flexible' entity with the &lt;strong&gt;ManagerId&lt;/strong&gt; property
(on one entity) and &lt;strong&gt;RelatedEmployee&lt;/strong&gt; property on the &lt;strong&gt;Project&lt;/strong&gt; kinds.&amp;nbsp;
This allows me to figure out later what objects are related to each other since we
can't model the CLR objects relationships directly.&amp;nbsp; Let's see how this was done.
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; SsdsEntity&amp;lt;T&amp;gt; &lt;span style="color: #0000ff"&gt;where&lt;/span&gt; T: &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; {
Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt;
_propertyBucket = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt;(); &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; SsdsEntity()
{ } [XmlIgnore] &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt;
PropertyBucket { get { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _propertyBucket;
} } [XmlAnyElement] &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; XElement[] Attributes
{ get { &lt;span style="color: #008000"&gt;//using XElement is much easier than XmlElement
to build&lt;/span&gt; &lt;span style="color: #008000"&gt;//take all properties on object instance
and build XElement&lt;/span&gt; var props = from prop &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T).GetProperties()
let val = prop.GetValue(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Entity, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;where&lt;/span&gt; prop.GetSetMethod()
!= &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; allowableTypes.Contains(prop.PropertyType)
&amp;amp;&amp;amp; val != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; select &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XElement(prop.Name, &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XAttribute(Constants.xsi
+ &lt;span style="color: #006080"&gt;"type"&lt;/span&gt;, XsdTypeResolver.Solve(prop.PropertyType)),
EncodeValue(val) ); &lt;span style="color: #008000"&gt;//Then stuff in any extra stuff you
want&lt;/span&gt; var extra = _propertyBucket.Select( e =&amp;gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XElement(e.Key, &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XAttribute(Constants.xsi
+ &lt;span style="color: #006080"&gt;"type"&lt;/span&gt;, XsdTypeResolver.Solve(e.Value.GetType())),
EncodeValue(e.Value) ) ); &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; props.Union(extra).ToArray();
} set { &lt;span style="color: #008000"&gt;//wrap the XElement[] with the name of the type&lt;/span&gt; var
xml = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XElement(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T).Name, &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;);
var xs = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlSerializer(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T)); &lt;span style="color: #008000"&gt;//xml.CreateReader()
cannot be used as it won't support base64 content&lt;/span&gt; XmlTextReader reader = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlTextReader(
xml.ToString(), XmlNodeType.Document, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; ); &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Entity
= (T)xs.Deserialize(reader); &lt;span style="color: #008000"&gt;//now deserialize the other
stuff left over into the property bucket...&lt;/span&gt; var stuff = from v &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;.AsEnumerable()
let props = &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T).GetProperties().Select(s
=&amp;gt; s.Name) &lt;span style="color: #0000ff"&gt;where&lt;/span&gt; !props.Contains(v.Name.ToString())
select v; &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var item &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; stuff)
{ _propertyBucket.Add( item.Name.ToString(), DecodeValue( item.Attribute(Constants.xsi
+ &lt;span style="color: #006080"&gt;"type"&lt;/span&gt;).Value, item.Value) ); } } } &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Add&amp;lt;K&amp;gt;(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; key,
K &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;) { &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!allowableTypes.Contains(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(K))) &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ArgumentException(
String.Format( &lt;span style="color: #006080"&gt;"Type {0} not supported in SsdsEntity"&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(K).Name)
); &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!_propertyBucket.ContainsKey(key)) { _propertyBucket.Add(key, &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;);
} &lt;span style="color: #0000ff"&gt;else&lt;/span&gt; { &lt;span style="color: #008000"&gt;//replace
the value&lt;/span&gt; _propertyBucket.Remove(key); _propertyBucket.Add(key, &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;);
} } }&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
I have omitted the parts of &lt;strong&gt;SsdsEntity&amp;lt;T&amp;gt;&lt;/strong&gt; from the first post
that didn't change.&amp;nbsp; The only other addition you don't see here is a helper method
called &lt;strong&gt;DecodeValue&lt;/strong&gt;, which as you might guess, interprets the string
value in XML and attempts to cast it to a CLR type based on the xsi:type that comes
back.
&lt;/p&gt;
&lt;p&gt;
All we did here was add a &lt;strong&gt;Dictionary&amp;lt;string, object&amp;gt;&lt;/strong&gt; property
called &lt;strong&gt;PropertyBucket&lt;/strong&gt; that holds our extra stuff we want to associate
with our T instance.&amp;nbsp; Then in the getter and setter for the &lt;strong&gt;XElement[]&lt;/strong&gt; property
called &lt;strong&gt;Attributes&lt;/strong&gt;, we are adding them into our array of &lt;strong&gt;XElement&lt;/strong&gt; as
well as pulling them back out on deserialization and stuffing them back into the Dictionary.&amp;nbsp;
With this simple addition, we have fixed our in flexibility (or lack thereof) problem.&amp;nbsp;
We are still limited to the simple scalar types, but as you can see you can work around
this in a lot of cases by decomposing the objects down enough to be able to recreate
them later.
&lt;/p&gt;
&lt;p&gt;
The &lt;strong&gt;Add&amp;lt;K&amp;gt;&lt;/strong&gt; method is a convenience only as we could operate
directly against the Dictionary.&amp;nbsp; I also could have chosen to keep the Dictionary
property bucket private and not expose it.&amp;nbsp; That would have worked just fine
for serialization, but I wanted to also be able to query it later.
&lt;/p&gt;
&lt;p&gt;
In my last post, I said I would introduce a library where all this code is coming
from, but I didn't realize at the time how long this post would be and that I still
need to cover querying.&amp;nbsp; So... next time, I will finish up this series by explaining
how the strongly typed query model works and how all these pieces fit together to
recompose the data back into objects (and release the library).
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=bdbc0cbd-e845-49e9-9e43-52a079bda687" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,bdbc0cbd-e845-49e9-9e43-52a079bda687.aspx</comments>
      <category>.NET</category>
      <category>Cloud Services</category>
      <category>SSDS</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=2021b648-8af2-4702-95f5-c5ec1455c1e1</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,2021b648-8af2-4702-95f5-c5ec1455c1e1.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,2021b648-8af2-4702-95f5-c5ec1455c1e1.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=2021b648-8af2-4702-95f5-c5ec1455c1e1</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <a href="http://dunnry.com/blog/SerializationInSSDS.aspx">Last time</a> we talked
about SQL Server Data Services and serializing objects, we discussed how easy it was
to use the <strong>XmlSerializer</strong> to deserialize objects using the REST interface. 
The problem was that when we serialized objects using the <strong>XmlSerializer</strong>,
it left out the xsi type declarations that we needed.  I gave two possible solutions
to this problem - one that used the <strong>XmlSerializer</strong> and 'fixed' the
output after the fact, and the other built the XML that we needed using XLINQ and
Reflection.
</p>
        <p>
Today, I am going to talk about a third technique that I have been using lately that
I like better.  It uses some of the previous techniques and leverages a few tricks
with <strong>XmlSerializer</strong> to get what I want.  First, let's start with
a POCO (plain ol' C# object) class that we would like to use with SSDS.
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">public</span>
            <span style="color: #0000ff">class</span> Foo
{ <span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> Name
{ get; set; } <span style="color: #0000ff">public</span><span style="color: #0000ff">int</span> Size
{ get; set; } <span style="color: #0000ff">public</span><span style="color: #0000ff">bool</span> IsPublic
{ get; set; } }</pre>
        </div>
        <p>
In it's correctly serialized form, it looks like this on the wire:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">&lt;</span>
            <span style="color: #800000">Foo</span>
            <span style="color: #ff0000">xmlns:s</span>
            <span style="color: #0000ff">="http://schemas.microsoft.com/sitka/2008/03/"</span>
            <span style="color: #ff0000">xmlns:xsi</span>
            <span style="color: #0000ff">="http://www.w3.org/2001/XMLSchema-instance"</span>
            <span style="color: #ff0000">xmlns:x</span>
            <span style="color: #0000ff">="http://www.w3.org/2001/XMLSchema"</span>
            <span style="color: #0000ff">&gt;</span>
            <span style="color: #0000ff">&lt;</span>
            <span style="color: #800000">s:Id</span>
            <span style="color: #0000ff">&gt;</span>someid<span style="color: #0000ff">&lt;/</span><span style="color: #800000">s:Id</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">s:Version</span><span style="color: #0000ff">&gt;</span>1<span style="color: #0000ff">&lt;/</span><span style="color: #800000">s:Version</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">Name</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:string"</span><span style="color: #0000ff">&gt;</span>My
Foo<span style="color: #0000ff">&lt;/</span><span style="color: #800000">Name</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">Size</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:decimal"</span><span style="color: #0000ff">&gt;</span>10<span style="color: #0000ff">&lt;/</span><span style="color: #800000">Size</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">IsPublic</span><span style="color: #ff0000">xsi:type</span><span style="color: #0000ff">="x:boolean"</span><span style="color: #0000ff">&gt;</span>false<span style="color: #0000ff">&lt;/</span><span style="color: #800000">IsPublic</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">Foo</span><span style="color: #0000ff">&gt;</span></pre>
        </div>
        <p>
You'll notice that we have the additional system metadata attributes "Id" and "Version"
in the markup.  We can account for the metadata attributes by doing something
cheesy like deriving from a base class:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">public</span>
            <span style="color: #0000ff">abstract</span>
            <span style="color: #0000ff">class</span> Cheese
{ <span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> Id
{ get; set; } <span style="color: #0000ff">public</span><span style="color: #0000ff">int</span> Version
{ get; set; } }</pre>
        </div>
        <p>
However this is very unnatural as our classes would all have to derive from our "Cheese"
abstract base class (ABC).
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">public</span>
            <span style="color: #0000ff">class</span> Foo
: Cheese { <span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> Name
{ get; set; } <span style="color: #0000ff">public</span><span style="color: #0000ff">int</span> Size
{ get; set; } <span style="color: #0000ff">public</span><span style="color: #0000ff">bool</span> IsPublic
{ get; set; } }</pre>
        </div>
        <p>
Developers familiar with remoting in .NET should be cringing right now as they remember
the hassles associated with deriving from <strong>MarshalByRefObject</strong>. 
In a world without multiple inheritance, this can be painful.  I want a model
where I can use arbitrary POCO objects (<a href="http://haacked.com/archive/2008/06/13/ras-syndrome.aspx">redundant</a>,
yes I know) and not be forced to derive from anything or do what I would otherwise
term unnatural acts.
</p>
        <p>
What if instead, we derived a generic entity that could contain any other entity?
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">public</span>
            <span style="color: #0000ff">class</span> SsdsEntity&lt;T&gt; <span style="color: #0000ff">where</span> T: <span style="color: #0000ff">class</span> { <span style="color: #0000ff">string</span> _kind; <span style="color: #0000ff">public</span> SsdsEntity()
{ } [XmlElement(Namespace = <span style="color: #006080">@"http://schemas.microsoft.com/sitka/2008/03/"</span>)] <span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> Id
{ get; set; } [XmlIgnore] <span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> Kind
{ get { <span style="color: #0000ff">if</span> (String.IsNullOrEmpty(_kind)) { _kind
= <span style="color: #0000ff">typeof</span>(T).Name; } <span style="color: #0000ff">return</span> _kind;
} set { _kind = <span style="color: #0000ff">value</span>; } } [XmlElement(Namespace
= <span style="color: #006080">@"http://schemas.microsoft.com/sitka/2008/03/"</span>)] <span style="color: #0000ff">public</span><span style="color: #0000ff">int</span> Version
{ get; set; } [XmlIgnore] <span style="color: #0000ff">public</span> T Entity { get;
set; } }</pre>
        </div>
        <p>
In this case, we have simply wrapped the POCO that we care about in a class that knows
about the specifics of the SSDS wire format (or more accurately could serialize down
to the wire format).
</p>
        <p>
This <strong>SsdsEntity&lt;T&gt;</strong> is easy to use and provides access to the
strongly typed object via the Entity property.
</p>
        <p>
          <a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/SerializationinSSDSRevisited_BEC9/foomembers_2.png">
            <img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="293" alt="foomembers" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/SerializationinSSDSRevisited_BEC9/foomembers_thumb.png" width="487" border="0" />
          </a>
        </p>
        <p>
Now, we just have to figure out how to serialize the <strong>SsdsEntity&lt;Foo&gt;</strong> object
and we know that the metadata attributes are taken care of and our original POCO object
that we care about is included.  I call it wrapping POCOs in a thin SSDS veneer.
</p>
        <p>
The trick to this is to add a bucket of XElement objects on the <strong>SsdsEntity&lt;T&gt;</strong> class
that will hold our public properties on our class T (i.e. 'Foo' class).  It looks
something like this:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">[XmlAnyElement]
<span style="color: #0000ff">public</span> XElement[]
Attributes { get { <span style="color: #008000">//using XElement is much easier than
XmlElement to build</span><span style="color: #008000">//take all properties on object
instance and build XElement</span> var props = from prop <span style="color: #0000ff">in</span><span style="color: #0000ff">typeof</span>(T).GetProperties()
let val = prop.GetValue(<span style="color: #0000ff">this</span>.Entity, <span style="color: #0000ff">null</span>) <span style="color: #0000ff">where</span> prop.GetSetMethod()
!= <span style="color: #0000ff">null</span> &amp;&amp; allowableTypes.Contains(prop.PropertyType)
&amp;&amp; val != <span style="color: #0000ff">null</span> select <span style="color: #0000ff">new</span> XElement(prop.Name, <span style="color: #0000ff">new</span> XAttribute(Constants.xsi
+ <span style="color: #006080">"type"</span>, XsdTypeResolver.Solve(prop.PropertyType)),
EncodeValue(val) ); <span style="color: #0000ff">return</span> props.ToArray(); }
set { <span style="color: #008000">//wrap the XElement[] with the name of the type</span> var
xml = <span style="color: #0000ff">new</span> XElement(<span style="color: #0000ff">typeof</span>(T).Name, <span style="color: #0000ff">value</span>);
var xs = <span style="color: #0000ff">new</span> XmlSerializer(<span style="color: #0000ff">typeof</span>(T)); <span style="color: #008000">//xml.CreateReader()
cannot be used as it won't support base64 content</span> XmlTextReader reader = <span style="color: #0000ff">new</span> XmlTextReader(
xml.ToString(), XmlNodeType.Document, <span style="color: #0000ff">null</span>); <span style="color: #0000ff">this</span>.Entity
= (T)xs.Deserialize(reader); } }</pre>
        </div>
        <p>
In the getter, we use Reflection and pull back a list of all the public properties
on the T object and build an array of <strong>XElement</strong>.  This is the
same technique I used in my first post on serialization.  The 'allowableTypes'
object is a <strong>HashSet&lt;Type&gt;</strong> that we use to figure out which property
types we can support in the service (DateTime, numeric, string, boolean, and byte[]). 
When this property serializes, the <strong>XElement</strong>s are simply added to
the markup.
</p>
        <p>
The <strong>EncodeValue</strong> method shown is a simple helper method that correctly
encodes string values, boolean, dates, integers, and byte[] values for the attribute. 
Finally, we are using a helper method that returns from a <strong>Dictionary&lt;Type,string&gt;</strong> the
correct xsi type for the required attribute (as determined from the property type).
</p>
        <p>
For deserialization, what happens is that the <strong>[XmlAnyElement]</strong> attribute
causes all unmapped attributes (in this case, all non-system metadata attributes)
to be collected in a collection of <strong>XElement</strong>.  When we deserialize,
if we simply wrap an enclosing element around this <strong>XElement</strong> collection,
it is exactly what we need for deserialization of T.  This is shown in the setter
implementation.
</p>
        <p>
It might look a little complicated, but now simple serialization will just work via
the <strong>XmlSerializer</strong>.  Here is one such implementation:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">public</span>
            <span style="color: #0000ff">string</span> Serialize(SsdsEntity&lt;T&gt;
entity) { <span style="color: #008000">//add a bunch of namespaces and override the
default ones too</span> XmlSerializerNamespaces namespaces = <span style="color: #0000ff">new</span> XmlSerializerNamespaces();
namespaces.Add(<span style="color: #006080">"s"</span>, Constants.ns.NamespaceName);
namespaces.Add(<span style="color: #006080">"x"</span>, Constants.x.NamespaceName);
namespaces.Add(<span style="color: #006080">"xsi"</span>, Constants.xsi.NamespaceName);
var xs = <span style="color: #0000ff">new</span> XmlSerializer( entity.GetType(), <span style="color: #0000ff">new</span> XmlRootAttribute(<span style="color: #0000ff">typeof</span>(T).Name)
); XmlWriterSettings xws = <span style="color: #0000ff">new</span> XmlWriterSettings();
xws.Indent = <span style="color: #0000ff">true</span>; xws.OmitXmlDeclaration = <span style="color: #0000ff">true</span>; <span style="color: #0000ff">using</span> (var
ms = <span style="color: #0000ff">new</span> MemoryStream()) { <span style="color: #0000ff">using</span> (XmlWriter
writer = XmlWriter.Create(ms, xws)) { xs.Serialize(writer, entity, namespaces); ms.Position
= 0; <span style="color: #008000">//reset to beginning</span><span style="color: #0000ff">using</span> (var
sr = <span style="color: #0000ff">new</span> StreamReader(ms)) { <span style="color: #0000ff">return</span> sr.ReadToEnd();
} } } }</pre>
        </div>
        <p>
Deserialization is even easier since we are starting with the XML representation and
don't have to build a Stream in memory.
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">public</span> SsdsEntity&lt;T&gt;
Deserialize(XElement node) { var xs = <span style="color: #0000ff">new</span> XmlSerializer( <span style="color: #0000ff">typeof</span>(SsdsEntity&lt;T&gt;), <span style="color: #0000ff">new</span> XmlRootAttribute(<span style="color: #0000ff">typeof</span>(T).Name)
); <span style="color: #008000">//xml.CreateReader() cannot be used as it won't support
base64 content</span> XmlTextReader reader = <span style="color: #0000ff">new</span> XmlTextReader(
node.ToString(), XmlNodeType.Document, <span style="color: #0000ff">null</span>); <span style="color: #0000ff">return</span> (SsdsEntity&lt;T&gt;)xs.Deserialize(reader);
}</pre>
        </div>
        <p>
If you notice, I am using an <strong>XmlTextReader</strong> to pass to the <strong>XmlSerializer</strong>. 
Unfortunately, the <strong>XmlReader</strong> from XLINQ does not support handling
of base64 content, so this workaround is necessary.
</p>
        <p>
At this point, we have a working serializer/deserializer that can handle arbitrary
POCOs.  There are some limitations of course:
</p>
        <ul>
          <li>
            <font color="#555555">We are limited to the same datatypes that SSDS supports. 
This also means nested objects and arrays are not directly supported.</font>
          </li>
          <li>
            <font color="#555555">We have lost a little of the 'flexible' in the Flexible Entity
(the E in the <a href="http://dunnry.com/blog/EntitiesContainersAndAuthorities.aspx">ACE
model</a>).  We now have a rigid schema defined by SSDS metadata and T public
properties and enforced on our objects.</font>
          </li>
        </ul>
        <p>
In my next post, I will attempt to address some of those limitations and I will introduce
a library that handles most of this for you.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=2021b648-8af2-4702-95f5-c5ec1455c1e1" />
      </body>
      <title>Working with Objects in SSDS Part 1</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,2021b648-8af2-4702-95f5-c5ec1455c1e1.aspx</guid>
      <link>http://dunnry.com/blog/2008/06/18/WorkingWithObjectsInSSDSPart1.aspx</link>
      <pubDate>Wed, 18 Jun 2008 03:17:10 GMT</pubDate>
      <description>&lt;p&gt;
&lt;a href="http://dunnry.com/blog/SerializationInSSDS.aspx"&gt;Last time&lt;/a&gt; we talked
about SQL Server Data Services and serializing objects, we discussed how easy it was
to use the &lt;strong&gt;XmlSerializer&lt;/strong&gt; to deserialize objects using the REST interface.&amp;nbsp;
The problem was that when we serialized objects using the &lt;strong&gt;XmlSerializer&lt;/strong&gt;,
it left out the xsi type declarations that we needed.&amp;nbsp; I gave two possible solutions
to this problem - one that used the &lt;strong&gt;XmlSerializer&lt;/strong&gt; and 'fixed' the
output after the fact, and the other built the XML that we needed using XLINQ and
Reflection.
&lt;/p&gt;
&lt;p&gt;
Today, I am going to talk about a third technique that I have been using lately that
I like better.&amp;nbsp; It uses some of the previous techniques and leverages a few tricks
with &lt;strong&gt;XmlSerializer&lt;/strong&gt; to get what I want.&amp;nbsp; First, let's start with
a POCO (plain ol' C# object) class that we would like to use with SSDS.
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Foo
{ &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Name
{ get; set; } &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Size
{ get; set; } &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; IsPublic
{ get; set; } }&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
In it's correctly serialized form, it looks like this on the wire:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Foo&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xmlns:s&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="http://schemas.microsoft.com/sitka/2008/03/"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xmlns:xsi&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xmlns:x&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="http://www.w3.org/2001/XMLSchema"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;someid&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;1&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;s:Version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Name&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:string"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;My
Foo&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Size&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:decimal"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;10&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Size&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;IsPublic&lt;/span&gt; &lt;span style="color: #ff0000"&gt;xsi:type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="x:boolean"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;false&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;IsPublic&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Foo&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
You'll notice that we have the additional system metadata attributes "Id" and "Version"
in the markup.&amp;nbsp; We can account for the metadata attributes by doing something
cheesy like deriving from a base class:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;abstract&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Cheese
{ &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Id
{ get; set; } &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Version
{ get; set; } }&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
However this is very unnatural as our classes would all have to derive from our "Cheese"
abstract base class (ABC).
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Foo
: Cheese { &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Name
{ get; set; } &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Size
{ get; set; } &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; IsPublic
{ get; set; } }&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Developers familiar with remoting in .NET should be cringing right now as they remember
the hassles associated with deriving from &lt;strong&gt;MarshalByRefObject&lt;/strong&gt;.&amp;nbsp;
In a world without multiple inheritance, this can be painful.&amp;nbsp; I want a model
where I can use arbitrary POCO objects (&lt;a href="http://haacked.com/archive/2008/06/13/ras-syndrome.aspx"&gt;redundant&lt;/a&gt;,
yes I know) and not be forced to derive from anything or do what I would otherwise
term unnatural acts.
&lt;/p&gt;
&lt;p&gt;
What if instead, we derived a generic entity that could contain any other entity?
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; SsdsEntity&amp;lt;T&amp;gt; &lt;span style="color: #0000ff"&gt;where&lt;/span&gt; T: &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; { &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; _kind; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; SsdsEntity()
{ } [XmlElement(Namespace = &lt;span style="color: #006080"&gt;@"http://schemas.microsoft.com/sitka/2008/03/"&lt;/span&gt;)] &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Id
{ get; set; } [XmlIgnore] &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Kind
{ get { &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (String.IsNullOrEmpty(_kind)) { _kind
= &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T).Name; } &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _kind;
} set { _kind = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;; } } [XmlElement(Namespace
= &lt;span style="color: #006080"&gt;@"http://schemas.microsoft.com/sitka/2008/03/"&lt;/span&gt;)] &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Version
{ get; set; } [XmlIgnore] &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; T Entity { get;
set; } }&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
In this case, we have simply wrapped the POCO that we care about in a class that knows
about the specifics of the SSDS wire format (or more accurately could serialize down
to the wire format).
&lt;/p&gt;
&lt;p&gt;
This &lt;strong&gt;SsdsEntity&amp;lt;T&amp;gt;&lt;/strong&gt; is easy to use and provides access to the
strongly typed object via the Entity property.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/SerializationinSSDSRevisited_BEC9/foomembers_2.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="293" alt="foomembers" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/SerializationinSSDSRevisited_BEC9/foomembers_thumb.png" width="487" border="0"&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
Now, we just have to figure out how to serialize the &lt;strong&gt;SsdsEntity&amp;lt;Foo&amp;gt;&lt;/strong&gt; object
and we know that the metadata attributes are taken care of and our original POCO object
that we care about is included.&amp;nbsp; I call it wrapping POCOs in a thin SSDS veneer.
&lt;/p&gt;
&lt;p&gt;
The trick to this is to add a bucket of XElement objects on the &lt;strong&gt;SsdsEntity&amp;lt;T&amp;gt;&lt;/strong&gt; class
that will hold our public properties on our class T (i.e. 'Foo' class).&amp;nbsp; It looks
something like this:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;[XmlAnyElement]
&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; XElement[]
Attributes { get { &lt;span style="color: #008000"&gt;//using XElement is much easier than
XmlElement to build&lt;/span&gt; &lt;span style="color: #008000"&gt;//take all properties on object
instance and build XElement&lt;/span&gt; var props = from prop &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T).GetProperties()
let val = prop.GetValue(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Entity, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;where&lt;/span&gt; prop.GetSetMethod()
!= &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; allowableTypes.Contains(prop.PropertyType)
&amp;amp;&amp;amp; val != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; select &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XElement(prop.Name, &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XAttribute(Constants.xsi
+ &lt;span style="color: #006080"&gt;"type"&lt;/span&gt;, XsdTypeResolver.Solve(prop.PropertyType)),
EncodeValue(val) ); &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; props.ToArray(); }
set { &lt;span style="color: #008000"&gt;//wrap the XElement[] with the name of the type&lt;/span&gt; var
xml = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XElement(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T).Name, &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;);
var xs = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlSerializer(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T)); &lt;span style="color: #008000"&gt;//xml.CreateReader()
cannot be used as it won't support base64 content&lt;/span&gt; XmlTextReader reader = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlTextReader(
xml.ToString(), XmlNodeType.Document, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;); &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Entity
= (T)xs.Deserialize(reader); } }&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
In the getter, we use Reflection and pull back a list of all the public properties
on the T object and build an array of &lt;strong&gt;XElement&lt;/strong&gt;.&amp;nbsp; This is the
same technique I used in my first post on serialization.&amp;nbsp; The 'allowableTypes'
object is a &lt;strong&gt;HashSet&amp;lt;Type&amp;gt;&lt;/strong&gt; that we use to figure out which property
types we can support in the service (DateTime, numeric, string, boolean, and byte[]).&amp;nbsp;
When this property serializes, the &lt;strong&gt;XElement&lt;/strong&gt;s are simply added to
the markup.
&lt;/p&gt;
&lt;p&gt;
The &lt;strong&gt;EncodeValue&lt;/strong&gt; method shown is a simple helper method that correctly
encodes string values, boolean, dates, integers, and byte[] values for the attribute.&amp;nbsp;
Finally, we are using a helper method that returns from a &lt;strong&gt;Dictionary&amp;lt;Type,string&amp;gt;&lt;/strong&gt; the
correct xsi type for the required attribute (as determined from the property type).
&lt;/p&gt;
&lt;p&gt;
For deserialization, what happens is that the &lt;strong&gt;[XmlAnyElement]&lt;/strong&gt; attribute
causes all unmapped attributes (in this case, all non-system metadata attributes)
to be collected in a collection of &lt;strong&gt;XElement&lt;/strong&gt;.&amp;nbsp; When we deserialize,
if we simply wrap an enclosing element around this &lt;strong&gt;XElement&lt;/strong&gt; collection,
it is exactly what we need for deserialization of T.&amp;nbsp; This is shown in the setter
implementation.
&lt;/p&gt;
&lt;p&gt;
It might look a little complicated, but now simple serialization will just work via
the &lt;strong&gt;XmlSerializer&lt;/strong&gt;.&amp;nbsp; Here is one such implementation:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Serialize(SsdsEntity&amp;lt;T&amp;gt;
entity) { &lt;span style="color: #008000"&gt;//add a bunch of namespaces and override the
default ones too&lt;/span&gt; XmlSerializerNamespaces namespaces = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlSerializerNamespaces();
namespaces.Add(&lt;span style="color: #006080"&gt;"s"&lt;/span&gt;, Constants.ns.NamespaceName);
namespaces.Add(&lt;span style="color: #006080"&gt;"x"&lt;/span&gt;, Constants.x.NamespaceName);
namespaces.Add(&lt;span style="color: #006080"&gt;"xsi"&lt;/span&gt;, Constants.xsi.NamespaceName);
var xs = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlSerializer( entity.GetType(), &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlRootAttribute(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T).Name)
); XmlWriterSettings xws = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlWriterSettings();
xws.Indent = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;; xws.OmitXmlDeclaration = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (var
ms = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MemoryStream()) { &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (XmlWriter
writer = XmlWriter.Create(ms, xws)) { xs.Serialize(writer, entity, namespaces); ms.Position
= 0; &lt;span style="color: #008000"&gt;//reset to beginning&lt;/span&gt; &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (var
sr = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; StreamReader(ms)) { &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; sr.ReadToEnd();
} } } }&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Deserialization is even easier since we are starting with the XML representation and
don't have to build a Stream in memory.
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; SsdsEntity&amp;lt;T&amp;gt;
Deserialize(XElement node) { var xs = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlSerializer( &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(SsdsEntity&amp;lt;T&amp;gt;), &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlRootAttribute(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(T).Name)
); &lt;span style="color: #008000"&gt;//xml.CreateReader() cannot be used as it won't support
base64 content&lt;/span&gt; XmlTextReader reader = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; XmlTextReader(
node.ToString(), XmlNodeType.Document, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;); &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; (SsdsEntity&amp;lt;T&amp;gt;)xs.Deserialize(reader);
}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
If you notice, I am using an &lt;strong&gt;XmlTextReader&lt;/strong&gt; to pass to the &lt;strong&gt;XmlSerializer&lt;/strong&gt;.&amp;nbsp;
Unfortunately, the &lt;strong&gt;XmlReader&lt;/strong&gt; from XLINQ does not support handling
of base64 content, so this workaround is necessary.
&lt;/p&gt;
&lt;p&gt;
At this point, we have a working serializer/deserializer that can handle arbitrary
POCOs.&amp;nbsp; There are some limitations of course:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;font color="#555555"&gt;We are limited to the same datatypes that SSDS supports.&amp;nbsp;
This also means nested objects and arrays are not directly supported.&lt;/font&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;font color="#555555"&gt;We have lost a little of the 'flexible' in the Flexible Entity
(the E in the &lt;a href="http://dunnry.com/blog/EntitiesContainersAndAuthorities.aspx"&gt;ACE
model&lt;/a&gt;).&amp;nbsp; We now have a rigid schema defined by SSDS metadata and T public
properties and enforced on our objects.&lt;/font&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
In my next post, I will attempt to address some of those limitations and I will introduce
a library that handles most of this for you.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=2021b648-8af2-4702-95f5-c5ec1455c1e1" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,2021b648-8af2-4702-95f5-c5ec1455c1e1.aspx</comments>
      <category>.NET</category>
      <category>Cloud Services</category>
      <category>Design</category>
      <category>SSDS</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=ada84666-9fb7-4142-8764-adff11fd8552</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,ada84666-9fb7-4142-8764-adff11fd8552.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,ada84666-9fb7-4142-8764-adff11fd8552.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=ada84666-9fb7-4142-8764-adff11fd8552</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I officially love <a href="http://www.linqpad.net/">LINQPad</a>.  Joe Albahari
has done a great job of introducing a light weight tool that is great for learning
and prototyping LINQ queries.  From what I gather, Joe and Ben Albahari built
this tool as part of <a href="http://www.amazon.com/exec/obidos/ASIN/0596527578/extemporaneou-20-20">their
book</a> offering.  It was so useful, it has taken on a life of its own.
</p>
        <p>
It may not be entirely obvious, but it turns out don't have to use LINQPad solely
for LINQ queries.  You can actually prototype any type of snippet of code. 
I have been using it now instead of <a href="http://www.sliver.com/dotnet/SnippetCompiler/">SnippetCompiler</a> (another
great quick snippet tool).
</p>
        <p>
As an example, here is how to use System.DirectoryServices snippets inside of LINQPad:
</p>
        <p>
Hit F4 to bring up the Advanced Query Properties Window
</p>
        <p>
          <a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/LINQPadnotjustforLINQ_9627/image_2.png">
            <img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="364" alt="image" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/LINQPadnotjustforLINQ_9627/image_thumb.png" width="461" border="0" />
          </a>
        </p>
        <p>
Add the System.DirectoryServices.dll reference in the Additional References window,
and then add "System.DirectoryServices" in the Additional Namespace Imports window.
</p>
        <p>
Now, just type your code normally and hit F5 when you are done:
</p>
        <p>
          <a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/LINQPadnotjustforLINQ_9627/image_6.png">
            <img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="352" alt="image" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/LINQPadnotjustforLINQ_9627/image_thumb_2.png" width="457" border="0" />
          </a> 
</p>
        <p>
This is a great little tool to have as you can query databases, build LINQ expressions,
and visually inspect the results that come back pretty easily.  Now, as you can
see you can also execute arbitrary code snippets as well.  Highly recommended.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=ada84666-9fb7-4142-8764-adff11fd8552" />
      </body>
      <title>LINQPad - not just for LINQ</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,ada84666-9fb7-4142-8764-adff11fd8552.aspx</guid>
      <link>http://dunnry.com/blog/2008/06/11/LINQPadNotJustForLINQ.aspx</link>
      <pubDate>Wed, 11 Jun 2008 17:47:50 GMT</pubDate>
      <description>&lt;p&gt;
I officially love &lt;a href="http://www.linqpad.net/"&gt;LINQPad&lt;/a&gt;.&amp;nbsp; Joe Albahari
has done a great job of introducing a light weight tool that is great for learning
and prototyping LINQ queries.&amp;nbsp; From what I gather, Joe and Ben Albahari built
this tool as part of &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0596527578/extemporaneou-20-20"&gt;their
book&lt;/a&gt; offering.&amp;nbsp; It was so useful, it has taken on a life of its own.
&lt;/p&gt;
&lt;p&gt;
It may not be entirely obvious, but it turns out don't have to use LINQPad solely
for LINQ queries.&amp;nbsp; You can actually prototype any type of snippet of code.&amp;nbsp;
I have been using it now instead of &lt;a href="http://www.sliver.com/dotnet/SnippetCompiler/"&gt;SnippetCompiler&lt;/a&gt; (another
great quick snippet tool).
&lt;/p&gt;
&lt;p&gt;
As an example, here is how to use System.DirectoryServices snippets inside of LINQPad:
&lt;/p&gt;
&lt;p&gt;
Hit F4 to bring up the Advanced Query Properties Window
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/LINQPadnotjustforLINQ_9627/image_2.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="364" alt="image" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/LINQPadnotjustforLINQ_9627/image_thumb.png" width="461" border="0"&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
Add the System.DirectoryServices.dll reference in the Additional References window,
and then add "System.DirectoryServices" in the Additional Namespace Imports window.
&lt;/p&gt;
&lt;p&gt;
Now, just type your code normally and hit F5 when you are done:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/LINQPadnotjustforLINQ_9627/image_6.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="352" alt="image" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/LINQPadnotjustforLINQ_9627/image_thumb_2.png" width="457" border="0"&gt;&lt;/a&gt;&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
This is a great little tool to have as you can query databases, build LINQ expressions,
and visually inspect the results that come back pretty easily.&amp;nbsp; Now, as you can
see you can also execute arbitrary code snippets as well.&amp;nbsp; Highly recommended.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=ada84666-9fb7-4142-8764-adff11fd8552" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,ada84666-9fb7-4142-8764-adff11fd8552.aspx</comments>
      <category>.NET</category>
      <category>LINQ</category>
      <category>Tips</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=982fe6ab-e507-4e65-b168-e8c2d3d72a9f</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,982fe6ab-e507-4e65-b168-e8c2d3d72a9f.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,982fe6ab-e507-4e65-b168-e8c2d3d72a9f.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=982fe6ab-e507-4e65-b168-e8c2d3d72a9f</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
A member in the <a href="http://directoryprogramming.net/forums/9/ShowForum.aspx">book's
forum</a> mentioned some code I had originally posted <a href="http://dunnry.com/blog/AsynchronousLDAPSearchingWithSystemDirectoryServicesProtocols.aspx">here</a> in
the blog for asynchronous, paged searches in System.DirectoryServices.Protocols (SDS.P). 
He questioned whether or not it was thread safe.  I honestly don't know - it
might not be as I didn't test it extensively.
</p>
        <p>
Regardless, I had actually moved on from that code and started using anonymous delegates
for callbacks instead of events.  I liked this pattern a bit better because it
also got rid of the shared resources.
</p>
        <p>
After reading Stephen Toub's <a href="http://msdn.microsoft.com/en-us/magazine/cc337900.aspx">article</a> on
asynchronous stream processing, I learned about the AsyncOperationManager which was
something I was missing in my implementation.  I have been doing a lot lately
with .NET 3.5, LINQ, and lambda expressions, so I also decided to rewrite the anonymous
delegates to lambda expressions.  That is not as big a change, but it is more
concise.
</p>
        <p>
I actively investigated using <a href="http://tomasp.net/blog/csharp-async.aspx">async
iterators</a>, but ultimately I decided closures seemed to be more intuitive for me. 
I might revisit this at some time and change my mind.  Here is my outcome:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">public</span>
            <span style="color: #0000ff">class</span> AsyncSearcher
{ LdapConnection _connect; <span style="color: #0000ff">public</span> AsyncSearcher(LdapConnection
connection) { <span style="color: #0000ff">this</span>._connect = connection; <span style="color: #0000ff">this</span>._connect.AutoBind
= <span style="color: #0000ff">true</span>; <span style="color: #008000">//will bind
on first search</span> } <span style="color: #0000ff">public</span><span style="color: #0000ff">void</span> BeginPagedSearch( <span style="color: #0000ff">string</span> baseDN, <span style="color: #0000ff">string</span> filter, <span style="color: #0000ff">string</span>[]
attribs, <span style="color: #0000ff">int</span> pageSize, Action&lt;SearchResponse&gt;
page, Action&lt;Exception&gt; completed ) { <span style="color: #0000ff">if</span> (page
== <span style="color: #0000ff">null</span>) <span style="color: #0000ff">throw</span><span style="color: #0000ff">new</span> ArgumentNullException(<span style="color: #006080">"page"</span>);
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(<span style="color: #0000ff">null</span>);
Action&lt;Exception&gt; done = e =&gt; { <span style="color: #0000ff">if</span> (completed
!= <span style="color: #0000ff">null</span>) asyncOp.Post(<span style="color: #0000ff">delegate</span> {
completed(e); }, <span style="color: #0000ff">null</span>); }; SearchRequest request
= <span style="color: #0000ff">new</span> SearchRequest( baseDN, filter, System.DirectoryServices.Protocols.SearchScope.Subtree,
attribs ); PageResultRequestControl prc = <span style="color: #0000ff">new</span> PageResultRequestControl(pageSize); <span style="color: #008000">//add
the paging control</span> request.Controls.Add(prc); AsyncCallback rc = <span style="color: #0000ff">null</span>;
rc = readResult =&gt; { <span style="color: #0000ff">try</span> { var response = (SearchResponse)_connect.EndSendRequest(readResult); <span style="color: #008000">//let
current thread handle results</span> asyncOp.Post(<span style="color: #0000ff">delegate</span> {
page(response); }, <span style="color: #0000ff">null</span>); var cookie = response.Controls
.Where(c =&gt; c <span style="color: #0000ff">is</span> PageResultResponseControl)
.Select(s =&gt; ((PageResultResponseControl)s).Cookie) .Single(); <span style="color: #0000ff">if</span> (cookie
!= <span style="color: #0000ff">null</span> &amp;&amp; cookie.Length != 0) { prc.Cookie
= cookie; _connect.BeginSendRequest( request, PartialResultProcessing.NoPartialResultSupport,
rc, <span style="color: #0000ff">null</span> ); } <span style="color: #0000ff">else</span> done(<span style="color: #0000ff">null</span>); <span style="color: #008000">//signal
complete</span> } <span style="color: #0000ff">catch</span> (Exception ex) { done(ex);
} }; <span style="color: #008000">//kick off async</span><span style="color: #0000ff">try</span> {
_connect.BeginSendRequest( request, PartialResultProcessing.NoPartialResultSupport,
rc, <span style="color: #0000ff">null</span> ); } <span style="color: #0000ff">catch</span> (Exception
ex) { done(ex); } } }</pre>
        </div>
        <p>
It can be consumed very easily using something like this:
</p>
        <div>
          <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <span style="color: #0000ff">class</span> Program
{ <span style="color: #0000ff">static</span> ManualResetEvent _resetEvent = <span style="color: #0000ff">new</span> ManualResetEvent(<span style="color: #0000ff">false</span>); <span style="color: #0000ff">static</span><span style="color: #0000ff">void</span> Main(<span style="color: #0000ff">string</span>[]
args) { <span style="color: #008000">//set these to your environment</span><span style="color: #0000ff">string</span> servername
= <span style="color: #006080">"server.yourdomain.com"</span>; <span style="color: #0000ff">string</span> baseDN
= <span style="color: #006080">"dc=yourdomain,dc=com"</span>; <span style="color: #0000ff">using</span> (LdapConnection
connection = CreateConnection(servername)) { AsyncSearcher searcher = <span style="color: #0000ff">new</span> AsyncSearcher(connection);
searcher.BeginPagedSearch( baseDN, <span style="color: #006080">"(sn=Dunn)"</span>, <span style="color: #0000ff">null</span>,
100, f =&gt; <span style="color: #008000">//runs per page</span> { <span style="color: #0000ff">foreach</span> (var
item <span style="color: #0000ff">in</span> f.Entries) { var entry = item <span style="color: #0000ff">as</span> SearchResultEntry; <span style="color: #0000ff">if</span> (entry
!= <span style="color: #0000ff">null</span>) { Console.WriteLine(entry.DistinguishedName);
} } }, c =&gt; <span style="color: #008000">//runs on error or when done</span> { <span style="color: #0000ff">if</span> (c
!= <span style="color: #0000ff">null</span>) Console.WriteLine(c.ToString()); Console.WriteLine(<span style="color: #006080">"Done"</span>);
_resetEvent.Set(); } ); _resetEvent.WaitOne(); } Console.WriteLine(); Console.WriteLine(<span style="color: #006080">"Finished....
Press Enter to Continue."</span>); Console.ReadLine(); } <span style="color: #0000ff">static</span> LdapConnection
CreateConnection(<span style="color: #0000ff">string</span> server) { LdapConnection
connect = <span style="color: #0000ff">new</span> LdapConnection( <span style="color: #0000ff">new</span> LdapDirectoryIdentifier(server), <span style="color: #0000ff">null</span>,
AuthType.Negotiate ); connect.SessionOptions.ProtocolVersion = 3; connect.SessionOptions.ReferralChasing
= ReferralChasingOptions.None; connect.SessionOptions.Sealing = <span style="color: #0000ff">true</span>;
connect.SessionOptions.Signing = <span style="color: #0000ff">true</span>; <span style="color: #0000ff">return</span> connect;
} } </pre>
        </div>
        <p>
 
</p>
        <p>
The important thing to note is that because everything is running asynchronously,
it is totally possible for the end delegate to be invoked before the paging delegate
has a chance to finish processing results (depending on how complicated your code
is).  You would need to compensate for this yourself.
</p>
        <p>
This client is a console application, so I am using a ManualResetEvent just to prevent
it from closing before finishing.  You wouldn't need to do this in a WinForms
or WPF app.
</p>
        <p>
I am sure there are other optimizations you could make to pass in parameters or even
other directory controls.  However, the general pattern should apply.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=982fe6ab-e507-4e65-b168-e8c2d3d72a9f" />
      </body>
      <title>Paged Asynchronous LDAP Searches Revisited</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,982fe6ab-e507-4e65-b168-e8c2d3d72a9f.aspx</guid>
      <link>http://dunnry.com/blog/2008/06/05/PagedAsynchronousLDAPSearchesRevisited.aspx</link>
      <pubDate>Thu, 05 Jun 2008 18:56:28 GMT</pubDate>
      <description>&lt;p&gt;
A member in the &lt;a href="http://directoryprogramming.net/forums/9/ShowForum.aspx"&gt;book's
forum&lt;/a&gt; mentioned some code I had originally posted &lt;a href="http://dunnry.com/blog/AsynchronousLDAPSearchingWithSystemDirectoryServicesProtocols.aspx"&gt;here&lt;/a&gt; in
the blog for asynchronous, paged searches in System.DirectoryServices.Protocols (SDS.P).&amp;nbsp;
He questioned whether or not it was thread safe.&amp;nbsp; I honestly don't know - it
might not be as I didn't test it extensively.
&lt;/p&gt;
&lt;p&gt;
Regardless, I had actually moved on from that code and started using anonymous delegates
for callbacks instead of events.&amp;nbsp; I liked this pattern a bit better because it
also got rid of the shared resources.
&lt;/p&gt;
&lt;p&gt;
After reading Stephen Toub's &lt;a href="http://msdn.microsoft.com/en-us/magazine/cc337900.aspx"&gt;article&lt;/a&gt; on
asynchronous stream processing, I learned about the AsyncOperationManager which was
something I was missing in my implementation.&amp;nbsp; I have been doing a lot lately
with .NET 3.5, LINQ, and lambda expressions, so I also decided to rewrite the anonymous
delegates to lambda expressions.&amp;nbsp; That is not as big a change, but it is more
concise.
&lt;/p&gt;
&lt;p&gt;
I actively investigated using &lt;a href="http://tomasp.net/blog/csharp-async.aspx"&gt;async
iterators&lt;/a&gt;, but ultimately I decided closures seemed to be more intuitive for me.&amp;nbsp;
I might revisit this at some time and change my mind.&amp;nbsp; Here is my outcome:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; AsyncSearcher
{ LdapConnection _connect; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; AsyncSearcher(LdapConnection
connection) { &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;._connect = connection; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;._connect.AutoBind
= &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;; &lt;span style="color: #008000"&gt;//will bind
on first search&lt;/span&gt; } &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; BeginPagedSearch( &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; baseDN, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; filter, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[]
attribs, &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; pageSize, Action&amp;lt;SearchResponse&amp;gt;
page, Action&amp;lt;Exception&amp;gt; completed ) { &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (page
== &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style="color: #006080"&gt;"page"&lt;/span&gt;);
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;);
Action&amp;lt;Exception&amp;gt; done = e =&amp;gt; { &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (completed
!= &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) asyncOp.Post(&lt;span style="color: #0000ff"&gt;delegate&lt;/span&gt; {
completed(e); }, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;); }; SearchRequest request
= &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SearchRequest( baseDN, filter, System.DirectoryServices.Protocols.SearchScope.Subtree,
attribs ); PageResultRequestControl prc = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; PageResultRequestControl(pageSize); &lt;span style="color: #008000"&gt;//add
the paging control&lt;/span&gt; request.Controls.Add(prc); AsyncCallback rc = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;
rc = readResult =&amp;gt; { &lt;span style="color: #0000ff"&gt;try&lt;/span&gt; { var response = (SearchResponse)_connect.EndSendRequest(readResult); &lt;span style="color: #008000"&gt;//let
current thread handle results&lt;/span&gt; asyncOp.Post(&lt;span style="color: #0000ff"&gt;delegate&lt;/span&gt; {
page(response); }, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;); var cookie = response.Controls
.Where(c =&amp;gt; c &lt;span style="color: #0000ff"&gt;is&lt;/span&gt; PageResultResponseControl)
.Select(s =&amp;gt; ((PageResultResponseControl)s).Cookie) .Single(); &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (cookie
!= &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; cookie.Length != 0) { prc.Cookie
= cookie; _connect.BeginSendRequest( request, PartialResultProcessing.NoPartialResultSupport,
rc, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; ); } &lt;span style="color: #0000ff"&gt;else&lt;/span&gt; done(&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;); &lt;span style="color: #008000"&gt;//signal
complete&lt;/span&gt; } &lt;span style="color: #0000ff"&gt;catch&lt;/span&gt; (Exception ex) { done(ex);
} }; &lt;span style="color: #008000"&gt;//kick off async&lt;/span&gt; &lt;span style="color: #0000ff"&gt;try&lt;/span&gt; {
_connect.BeginSendRequest( request, PartialResultProcessing.NoPartialResultSupport,
rc, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; ); } &lt;span style="color: #0000ff"&gt;catch&lt;/span&gt; (Exception
ex) { done(ex); } } }&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
It can be consumed very easily using something like this:
&lt;/p&gt;
&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Program
{ &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; ManualResetEvent _resetEvent = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ManualResetEvent(&lt;span style="color: #0000ff"&gt;false&lt;/span&gt;); &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Main(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[]
args) { &lt;span style="color: #008000"&gt;//set these to your environment&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; servername
= &lt;span style="color: #006080"&gt;"server.yourdomain.com"&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; baseDN
= &lt;span style="color: #006080"&gt;"dc=yourdomain,dc=com"&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (LdapConnection
connection = CreateConnection(servername)) { AsyncSearcher searcher = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; AsyncSearcher(connection);
searcher.BeginPagedSearch( baseDN, &lt;span style="color: #006080"&gt;"(sn=Dunn)"&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;,
100, f =&amp;gt; &lt;span style="color: #008000"&gt;//runs per page&lt;/span&gt; { &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var
item &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; f.Entries) { var entry = item &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; SearchResultEntry; &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (entry
!= &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) { Console.WriteLine(entry.DistinguishedName);
} } }, c =&amp;gt; &lt;span style="color: #008000"&gt;//runs on error or when done&lt;/span&gt; { &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (c
!= &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) Console.WriteLine(c.ToString()); Console.WriteLine(&lt;span style="color: #006080"&gt;"Done"&lt;/span&gt;);
_resetEvent.Set(); } ); _resetEvent.WaitOne(); } Console.WriteLine(); Console.WriteLine(&lt;span style="color: #006080"&gt;"Finished....
Press Enter to Continue."&lt;/span&gt;); Console.ReadLine(); } &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; LdapConnection
CreateConnection(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; server) { LdapConnection
connect = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; LdapConnection( &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; LdapDirectoryIdentifier(server), &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;,
AuthType.Negotiate ); connect.SessionOptions.ProtocolVersion = 3; connect.SessionOptions.ReferralChasing
= ReferralChasingOptions.None; connect.SessionOptions.Sealing = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;
connect.SessionOptions.Signing = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; connect;
} } &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
The important thing to note is that because everything is running asynchronously,
it is totally possible for the end delegate to be invoked before the paging delegate
has a chance to finish processing results (depending on how complicated your code
is).&amp;nbsp; You would need to compensate for this yourself.
&lt;/p&gt;
&lt;p&gt;
This client is a console application, so I am using a ManualResetEvent just to prevent
it from closing before finishing.&amp;nbsp; You wouldn't need to do this in a WinForms
or WPF app.
&lt;/p&gt;
&lt;p&gt;
I am sure there are other optimizations you could make to pass in parameters or even
other directory controls.&amp;nbsp; However, the general pattern should apply.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=982fe6ab-e507-4e65-b168-e8c2d3d72a9f" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,982fe6ab-e507-4e65-b168-e8c2d3d72a9f.aspx</comments>
      <category>.NET</category>
      <category>Active Directory</category>
      <category>LDAP</category>
      <category>Protocols</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=6d66af42-11f1-4b07-a4a6-ab83fa44be0a</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,6d66af42-11f1-4b07-a4a6-ab83fa44be0a.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,6d66af42-11f1-4b07-a4a6-ab83fa44be0a.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=6d66af42-11f1-4b07-a4a6-ab83fa44be0a</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I just posted the first version of <a href="http://www.codeplex.com/phluffyfotos">PhluffyFotos</a>,
our SQL Server Data Services (SSDS) sample app to CodePlex.  PhluffyFotos is
a photo sharing site that allows users to upload photos and metadata (tags, description)
to SSDS for storage.  As the service gets more features and is updated, the sample
will be rev'd as well.
</p>
        <p>
Points of interest that will likely also be blog posts in themselves:
</p>
        <ul>
          <li>
This sample has a LINQ-to-SSDS provider in it.  You will notice we don't use
any strings for queries, but rather lambda expressions.  I had a lot of fun writing
the first version of this and I would expect that there are a few more revisions here
to go.  Of course, <a href="http://blogs.msdn.com/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx">Matt
Warren</a> should get a ton of credit here for providing the base implementation.</li>
          <li>
This sample also uses a very simplistic ASP.NET Role provider for SSDS.  Likely
updates here will include encryption and hashing support.</li>
          <li>
We have a number of Powershell cmdlets included for managing authorities and containers.</li>
        </ul>
        <p>
I have many other ideas for this app as time progresses, so you should check back
from time to time to see the updates.
</p>
        <p>
In case anyone was wondering about the name: clouds are fluffy... get it?
</p>
        <p>
          <strong>
            <em>You need to have SSDS credentials to run this sample.  If you don't
have credentials yet, you can see an online version until then at <a href="http://www.phluffyfotos.com">http://www.phluffyfotos.com</a></em>
          </strong>
        </p>
        <p>
Even if you don' t have access to SSDS credentials yet, the code is worth taking a
look.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=6d66af42-11f1-4b07-a4a6-ab83fa44be0a" />
      </body>
      <title>PhluffyFotos Sample Available</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,6d66af42-11f1-4b07-a4a6-ab83fa44be0a.aspx</guid>
      <link>http://dunnry.com/blog/2008/04/09/PhluffyFotosSampleAvailable.aspx</link>
      <pubDate>Wed, 09 Apr 2008 19:02:37 GMT</pubDate>
      <description>&lt;p&gt;
I just posted the first version of &lt;a href="http://www.codeplex.com/phluffyfotos"&gt;PhluffyFotos&lt;/a&gt;,
our SQL Server Data Services (SSDS) sample app to CodePlex.&amp;nbsp; PhluffyFotos is
a photo sharing site that allows users to upload photos and metadata (tags, description)
to SSDS for storage.&amp;nbsp; As the service gets more features and is updated, the sample
will be rev'd as well.
&lt;/p&gt;
&lt;p&gt;
Points of interest that will likely also be blog posts in themselves:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
This sample has a LINQ-to-SSDS provider in it.&amp;nbsp; You will notice we don't use
any strings for queries, but rather lambda expressions.&amp;nbsp; I had a lot of fun writing
the first version of this and I would expect that there are a few more revisions here
to go.&amp;nbsp; Of course, &lt;a href="http://blogs.msdn.com/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx"&gt;Matt
Warren&lt;/a&gt; should get a ton of credit here for providing the base implementation.&lt;/li&gt;
&lt;li&gt;
This sample also uses a very simplistic ASP.NET Role provider for SSDS.&amp;nbsp; Likely
updates here will include encryption and hashing support.&lt;/li&gt;
&lt;li&gt;
We have a number of Powershell cmdlets included for managing authorities and containers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
I have many other ideas for this app as time progresses, so you should check back
from time to time to see the updates.
&lt;/p&gt;
&lt;p&gt;
In case anyone was wondering about the name: clouds are fluffy... get it?
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;&lt;em&gt;You need to have SSDS credentials to run this sample.&amp;nbsp; If you don't
have credentials yet, you can see an online version until then at &lt;a href="http://www.phluffyfotos.com"&gt;http://www.phluffyfotos.com&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
Even if you don' t have access to SSDS credentials yet, the code is worth taking a
look.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=6d66af42-11f1-4b07-a4a6-ab83fa44be0a" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,6d66af42-11f1-4b07-a4a6-ab83fa44be0a.aspx</comments>
      <category>.NET</category>
      <category>Cloud Services</category>
      <category>SSDS</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=b763b823-288e-4b14-9337-72f0355f29cb</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,b763b823-288e-4b14-9337-72f0355f29cb.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,b763b823-288e-4b14-9337-72f0355f29cb.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=b763b823-288e-4b14-9337-72f0355f29cb</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
If you are interested in learning more about Visual Studio 2008, make sure you check
out the <a href="http://go.microsoft.com/?linkid=7602397">Visual Studio 2008 Training
Kit</a>.  Weighing in at roughly 120MB compressed, it contains, "<em>a full
5-days of technical content including 20 hands-on labs, 28 presentations, and 20 scripted
demos.   The technologies covered in the kit include:  LINQ, C# 3.0,
VB 9, WCF, WF, WPF, Windows CardSpace, Silverlight, ASP.NET Ajax, .NET Compact Framework
3.5, VSTO 3.0, Visual Studio Team System, and Team Foundation Server</em>".
</p>
        <p>
Naturally, you will want to have a machine setup to run all these labs and samples...
so, thanks to the hard work of <a href="http://blogs.msdn.com/daiken/default.aspx">David</a> and <a href="http://blogs.msdn.com/jamescon/default.aspx">James</a>,
you can now download a VPC with Vista, Visual Studio 2008 (trial), and the .NET 3.5
framework pre-loaded and ready to run.  <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=3ca34c20-0b28-4c1a-87cd-33ce952611e7&amp;displaylang=en">Get
it here</a>.
</p>
        <p>
You want more?  Ok, how about 17 training videos describing the technologies
and running through a number of demos?  <a href="http://channel9.msdn.com/Showforum.aspx?forumid=38&amp;tagid=267">Get
those here</a>.
</p>
        <p>
These are truly some great resources to get you jumpstarted!
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=b763b823-288e-4b14-9337-72f0355f29cb" />
      </body>
      <title>.NET 3.5 VPC and Resources Available</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,b763b823-288e-4b14-9337-72f0355f29cb.aspx</guid>
      <link>http://dunnry.com/blog/2007/12/03/NET35VPCAndResourcesAvailable.aspx</link>
      <pubDate>Mon, 03 Dec 2007 19:11:56 GMT</pubDate>
      <description>&lt;p&gt;
If you are interested in learning more about Visual Studio 2008, make sure you check
out the &lt;a href="http://go.microsoft.com/?linkid=7602397"&gt;Visual Studio 2008 Training
Kit&lt;/a&gt;.&amp;#160; Weighing in at roughly 120MB compressed, it contains, &amp;quot;&lt;em&gt;a full
5-days of technical content including 20 hands-on labs, 28 presentations, and 20 scripted
demos.&amp;#160;&amp;#160; The technologies covered in the kit include:&amp;#160; LINQ, C# 3.0,
VB 9, WCF, WF, WPF, Windows CardSpace, Silverlight, ASP.NET Ajax, .NET Compact Framework
3.5, VSTO 3.0, Visual Studio Team System, and Team Foundation Server&lt;/em&gt;&amp;quot;.
&lt;/p&gt;
&lt;p&gt;
Naturally, you will want to have a machine setup to run all these labs and samples...
so, thanks to the hard work of &lt;a href="http://blogs.msdn.com/daiken/default.aspx"&gt;David&lt;/a&gt; and &lt;a href="http://blogs.msdn.com/jamescon/default.aspx"&gt;James&lt;/a&gt;,
you can now download a VPC with Vista, Visual Studio 2008 (trial), and the .NET 3.5
framework pre-loaded and ready to run.&amp;#160; &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=3ca34c20-0b28-4c1a-87cd-33ce952611e7&amp;amp;displaylang=en"&gt;Get
it here&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
You want more?&amp;#160; Ok, how about 17 training videos describing the technologies
and running through a number of demos?&amp;#160; &lt;a href="http://channel9.msdn.com/Showforum.aspx?forumid=38&amp;amp;tagid=267"&gt;Get
those here&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
These are truly some great resources to get you jumpstarted!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=b763b823-288e-4b14-9337-72f0355f29cb" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,b763b823-288e-4b14-9337-72f0355f29cb.aspx</comments>
      <category>.NET</category>
      <category>LINQ</category>
      <category>VS.NET</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=b1e8405e-8e34-4692-83bf-10fa2e69e6c4</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,b1e8405e-8e34-4692-83bf-10fa2e69e6c4.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,b1e8405e-8e34-4692-83bf-10fa2e69e6c4.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=b1e8405e-8e34-4692-83bf-10fa2e69e6c4</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
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 "<a href="http://msdn2.microsoft.com/en-us/library/ms677625.aspx">Overview
of Change Tracking Techniques"</a>.  In summary:
</p>
        <ol>
          <li>
            <a href="http://msdn2.microsoft.com/en-us/library/ms677627.aspx">Polling for Changes
using uSNChanged</a>. 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. 
<ul><li>
Benefits 
<ul><li>
This is the most compatible way.  All languages and all versions of .NET support
this way since it is a simple search. 
</li></ul></li><li>
Disadvantages 
<ul><li>
There is a lot here for the developer to take care of.  You get the entire object
back, and you must determine what has changed on the object (and if you care about
that change). 
</li><li>
Dealing with deleted objects is a pain. 
</li><li>
This is a polling technique, so it is only as real-time as how often you query. 
This can be a good thing depending on the application. Note, intermediate values are
not tracked here either. 
</li></ul></li></ul></li>
          <li>
            <a href="http://msdn2.microsoft.com/en-us/library/ms677626.aspx">Polling for Changes
Using the DirSync Control</a>.  This technique uses the ADS_SEARCHPREF_DIRSYNC
option in ADSI and the LDAP_SERVER_DIRSYNC_OID control under the covers.  Simply
make an initial search, store the cookie, and then later search again and send the
cookie.  It will return only the objects that have changed. 
<ul><li>
Benefits 
<ul><li>
This is an easy model to follow.  Both System.DirectoryServices and System.DirectoryServices.Protocols
support this option. 
</li><li>
Filtering can reduce what you need to bother with.  As an example, if my initial
search is for all users "(objectClass=user)", I can subsequently filter on polling
with "(sn=dunn)" and only get back the combination of both filters, instead of having
to deal with everything from the intial filter. 
</li><li>
Windows 2003+ option removes the administrative limitation for using this option (object
security). 
</li><li>
Windows 2003+ option will also give you the ability to return only the incremental
values that have changed in large multi-valued attributes.  This is a really
nice feature. 
</li><li>
Deals well with deleted objects. 
</li></ul></li><li>
Disadvantages 
<ul><li>
This is .NET 2.0+ or later only option.  Users of .NET 1.1 will need to use uSNChanged
Tracking.  Scripting languages cannot use this method. 
</li><li>
You can only scope the search to a partition.  If you want to track only a particular
OU or object, you must sort out those results yourself later. 
</li><li>
Using this with non-Windows 2003 mode domains comes with the restriction that you
must have replication get changes permissions (default only admin) to use. 
</li><li>
This is a polling technique.  It does not track intermediate values either. 
So, if an object you want to track changes between the searches multiple times, you
will only get the last change.  This can be an advantage depending on the application. 
</li></ul></li></ul></li>
          <li>
            <a href="http://msdn2.microsoft.com/en-us/library/aa772153.aspx">Change Notifications
in Active Directory</a>.  This technique registers a search on a separate thread
that will receive notifications when any object changes that matches the filter. 
You can register up to 5 notifications per async connection. 
<ul><li>
Benefits 
<ul><li>
Instant notification.  The other techniques require polling. 
</li><li>
Because this is a notification, you will get all changes, even the intermediate ones
that would have been lost in the other two techniques. 
</li></ul></li><li>
Disadvantages 
<ul><li>
Relatively resource intensive.  You don't want to do a whole ton of these as
it could cause scalability issues with your controller. 
</li><li>
This only tells you if the object has changed, but it does not tell you what the change
was.  You need to figure out if the attribute you care about has changed or not. 
That being said, it is pretty easy to tell if the object has been deleted (easier
than uSNChanged polling at least). 
</li><li>
You can only do this in unmanaged code or with System.DirectoryServices.Protocols. 
</li></ul></li></ul></li>
        </ol>
        <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.
</p>
        <p>
My first thought on writing this was to use the <a href="http://msdn2.microsoft.com/en-us/library/ms676877.aspx">sample
code</a> 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:
</p>
        <div>
          <div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #0000ff">public</span>
              <span style="color: #0000ff">class</span> ChangeNotifier
: IDisposable</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">{</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    LdapConnection _connection;</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    HashSet&lt;IAsyncResult&gt; _results = <span style="color: #0000ff">new</span> HashSet&lt;IAsyncResult&gt;();</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
            </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
              <span style="color: #0000ff">public</span> ChangeNotifier(LdapConnection
connection)</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    {</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        _connection = connection;</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        _connection.AutoBind = <span style="color: #0000ff">true</span>;</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    }</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
              <span style="color: #0000ff">public</span>
              <span style="color: #0000ff">void</span> Register(<span style="color: #0000ff">string</span> dn,
SearchScope scope)</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    {</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        SearchRequest request = <span style="color: #0000ff">new</span> SearchRequest(</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            dn, <span style="color: #008000">//root
the search here</span></pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
              <span style="color: #006080">"(objectClass=*)"</span>, <span style="color: #008000">//very
inclusive</span></pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            scope, <span style="color: #008000">//any
scope works</span></pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
              <span style="color: #0000ff">null</span>
              <span style="color: #008000">//we
are interested in all attributes</span>
            </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            );</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #008000">//register
our search</span>
            </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        request.Controls.Add(<span style="color: #0000ff">new</span> DirectoryNotificationControl());</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
              <span style="color: #008000">//we
will send this async and register our callback</span>
            </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #008000">//note
how we would like to have partial results</span>
            </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        IAsyncResult result = _connection.BeginSendRequest(</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            request,</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">            TimeSpan.FromDays(1), <span style="color: #008000">//set
timeout to a day...</span></pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            PartialResultProcessing.ReturnPartialResultsAndNotifyCallback,</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">            Notify,</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            request</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">            );</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
              <span style="color: #008000">//store
the hash for disposal later</span>
            </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        _results.Add(result);</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    }</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
              <span style="color: #0000ff">private</span>
              <span style="color: #0000ff">void</span> Notify(IAsyncResult
result)</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    {</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
              <span style="color: #008000">//since
our search is long running, we don't want to use EndSendRequest</span>
            </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        PartialResultsCollection prc = _connection.GetPartialResults(result);</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #0000ff">foreach</span> (SearchResultEntry
entry <span style="color: #0000ff">in</span> prc)</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        {</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            OnObjectChanged(<span style="color: #0000ff">new</span> ObjectChangedEventArgs(entry));</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        }</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    }</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #0000ff">private</span>
              <span style="color: #0000ff">void</span> OnObjectChanged(ObjectChangedEventArgs
args)</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    {</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #0000ff">if</span> (ObjectChanged
!= <span style="color: #0000ff">null</span>)</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        {</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            ObjectChanged(<span style="color: #0000ff">this</span>,
args);</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        }</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    }</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #0000ff">public</span>
              <span style="color: #0000ff">event</span> EventHandler&lt;ObjectChangedEventArgs&gt;
ObjectChanged;</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #cc6633">#region</span> IDisposable
Members</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #0000ff">public</span>
              <span style="color: #0000ff">void</span> Dispose()</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    {</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #0000ff">foreach</span> (var
result <span style="color: #0000ff">in</span> _results)</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        {</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #008000">//end
each async search</span>
            </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">            _connection.Abort(result);</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        }</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    }</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
              <span style="color: #cc6633">#endregion</span>
            </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">}</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #0000ff">public</span>
              <span style="color: #0000ff">class</span> ObjectChangedEventArgs
: EventArgs</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">{</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #0000ff">public</span> ObjectChangedEventArgs(SearchResultEntry
entry)</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    {</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        Result = entry;</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    }</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
              <span style="color: #0000ff">public</span> SearchResultEntry
Result { get; set;}</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">}</pre>
          </div>
        </div>
        <p>
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:
</p>
        <div>
          <div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #0000ff">static</span>
              <span style="color: #0000ff">void</span> Main(<span style="color: #0000ff">string</span>[]
args)</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">{</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #0000ff">using</span> (LdapConnection
connect = CreateConnection(<span style="color: #006080">"localhost"</span>))</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    {</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #0000ff">using</span> (ChangeNotifier
notifier = <span style="color: #0000ff">new</span> ChangeNotifier(connect))</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        {</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #008000">//register
some objects for notifications (limit 5)</span>
            </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">            notifier.Register(<span style="color: #006080">"dc=dunnry,dc=net"</span>,
SearchScope.OneLevel);</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            notifier.Register(<span style="color: #006080">"cn=testuser1,ou=users,dc=dunnry,dc=net"</span>,
SearchScope.Base);</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            notifier.ObjectChanged += <span style="color: #0000ff">new</span> EventHandler&lt;ObjectChangedEventArgs&gt;(notifier_ObjectChanged);</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            Console.WriteLine(<span style="color: #006080">"Waiting
for changes..."</span>);</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">            Console.WriteLine();</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            Console.ReadLine();</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        }</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    }</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">}</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"> </pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
              <span style="color: #0000ff">static</span>
              <span style="color: #0000ff">void</span> notifier_ObjectChanged(<span style="color: #0000ff">object</span> sender,
ObjectChangedEventArgs e)</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">{</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    Console.WriteLine(e.Result.DistinguishedName);</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #0000ff">foreach</span> (<span style="color: #0000ff">string</span> attrib <span style="color: #0000ff">in</span> e.Result.Attributes.AttributeNames)</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    {</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">
              <span style="color: #0000ff">foreach</span> (var
item <span style="color: #0000ff">in</span> e.Result.Attributes[attrib].GetValues(<span style="color: #0000ff">typeof</span>(<span style="color: #0000ff">string</span>)))</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        {</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            Console.WriteLine(<span style="color: #006080">"\t{0}:
{1}"</span>, attrib, item);</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        }</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    }</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    Console.WriteLine();</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    Console.WriteLine(<span style="color: #006080">"===================="</span>);</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    Console.WriteLine();</pre>
            <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">}</pre>
          </div>
        </div>
        <p>
And there you have it... change notifications in .NET.  You can also <a href="http://cid-4225352e17899c6d.skydrive.live.com/self.aspx/Public/ChangeNotifications.zip">download
my project file</a> for Visual Studio 2008.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=b1e8405e-8e34-4692-83bf-10fa2e69e6c4" />
      </body>
      <title>Implementing Change Notifications in .NET</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,b1e8405e-8e34-4692-83bf-10fa2e69e6c4.aspx</guid>
      <link>http://dunnry.com/blog/2007/10/30/ImplementingChangeNotificationsInNET.aspx</link>
      <pubDate>Tue, 30 Oct 2007 18:14:23 GMT</pubDate>
      <description>&lt;p&gt;
There are three ways of figuring out things that have changed in Active Directory
(or ADAM).&amp;nbsp; These have been documented for some time over at MSDN in the aptly
titled "&lt;a href="http://msdn2.microsoft.com/en-us/library/ms677625.aspx"&gt;Overview
of Change Tracking Techniques"&lt;/a&gt;.&amp;nbsp; In summary:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;a href="http://msdn2.microsoft.com/en-us/library/ms677627.aspx"&gt;Polling for Changes
using uSNChanged&lt;/a&gt;. This technique checks the 'highestCommittedUSN' value to start
and then performs searches for 'uSNChanged' values that are higher subsequently.&amp;nbsp;
The 'uSNChanged' attribute is not replicated between domain controllers, so you must
go back to the same domain controller each time for consistency.&amp;nbsp; 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. 
&lt;ul&gt;
&lt;li&gt;
Benefits 
&lt;ul&gt;
&lt;li&gt;
This is the most compatible way.&amp;nbsp; All languages and all versions of .NET support
this way since it is a simple search. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;
Disadvantages 
&lt;ul&gt;
&lt;li&gt;
There is a lot here for the developer to take care of.&amp;nbsp; You get the entire object
back, and you must determine what has changed on the object (and if you care about
that change). 
&lt;li&gt;
Dealing with deleted objects is a pain. 
&lt;li&gt;
This is a polling technique, so it is only as real-time as how often you query.&amp;nbsp;
This can be a good thing depending on the application. Note, intermediate values are
not tracked here either. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;
&lt;a href="http://msdn2.microsoft.com/en-us/library/ms677626.aspx"&gt;Polling for Changes
Using the DirSync Control&lt;/a&gt;.&amp;nbsp; This technique uses the ADS_SEARCHPREF_DIRSYNC
option in ADSI and the LDAP_SERVER_DIRSYNC_OID control under the covers.&amp;nbsp; Simply
make an initial search, store the cookie, and then later search again and send the
cookie.&amp;nbsp; It will return only the objects that have changed. 
&lt;ul&gt;
&lt;li&gt;
Benefits 
&lt;ul&gt;
&lt;li&gt;
This is an easy model to follow.&amp;nbsp; Both System.DirectoryServices and System.DirectoryServices.Protocols
support this option. 
&lt;li&gt;
Filtering can reduce what you need to bother with.&amp;nbsp; As an example, if my initial
search is for all users "(objectClass=user)", I can subsequently filter on polling
with "(sn=dunn)" and only get back the combination of both filters, instead of having
to deal with everything from the intial filter. 
&lt;li&gt;
Windows 2003+ option removes the administrative limitation for using this option (object
security). 
&lt;li&gt;
Windows 2003+ option will also give you the ability to return only the incremental
values that have changed in large multi-valued attributes.&amp;nbsp; This is a really
nice feature. 
&lt;li&gt;
Deals well with deleted objects. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;
Disadvantages 
&lt;ul&gt;
&lt;li&gt;
This is .NET 2.0+ or later only option.&amp;nbsp; Users of .NET 1.1 will need to use uSNChanged
Tracking.&amp;nbsp; Scripting languages cannot use this method. 
&lt;li&gt;
You can only scope the search to a partition.&amp;nbsp; If you want to track only a particular
OU or object, you must sort out those results yourself later. 
&lt;li&gt;
Using this with non-Windows 2003 mode domains comes with the restriction that you
must have replication get changes permissions (default only admin) to use. 
&lt;li&gt;
This is a polling technique.&amp;nbsp; It does not track intermediate values either.&amp;nbsp;
So, if an object you want to track changes between the searches multiple times, you
will only get the last change.&amp;nbsp; This can be an advantage depending on the application. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;
&lt;a href="http://msdn2.microsoft.com/en-us/library/aa772153.aspx"&gt;Change Notifications
in Active Directory&lt;/a&gt;.&amp;nbsp; This technique registers a search on a separate thread
that will receive notifications when any object changes that matches the filter.&amp;nbsp;
You can register up to 5 notifications per async connection. 
&lt;ul&gt;
&lt;li&gt;
Benefits 
&lt;ul&gt;
&lt;li&gt;
Instant notification.&amp;nbsp; The other techniques require polling. 
&lt;li&gt;
Because this is a notification, you will get all changes, even the intermediate ones
that would have been lost in the other two techniques. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;
Disadvantages 
&lt;ul&gt;
&lt;li&gt;
Relatively resource intensive.&amp;nbsp; You don't want to do a whole ton of these as
it could cause scalability issues with your controller. 
&lt;li&gt;
This only tells you if the object has changed, but it does not tell you what the change
was.&amp;nbsp; You need to figure out if the attribute you care about has changed or not.&amp;nbsp;
That being said, it is pretty easy to tell if the object has been deleted (easier
than uSNChanged polling at least). 
&lt;li&gt;
You can only do this in unmanaged code or with System.DirectoryServices.Protocols. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
For the most part, I have found that DirSync has fit the bill for me in virtually
every situation.&amp;nbsp; I never bothered to try any of the other techniques.&amp;nbsp;
However, a reader asked if there was a way to do the change notifications in .NET.&amp;nbsp;
I figured it was possible using SDS.P, but had never tried it.&amp;nbsp; Turns out, it
is possible and actually not too hard to do.
&lt;/p&gt;
&lt;p&gt;
My first thought on writing this was to use the &lt;a href="http://msdn2.microsoft.com/en-us/library/ms676877.aspx"&gt;sample
code&lt;/a&gt; found on MSDN (and referenced from option #3) and simply convert this to
System.DirectoryServices.Protocols.&amp;nbsp; This turned out to be a dead end.&amp;nbsp;
The way you do it in SDS.P and the way the sample code works are different enough
that it is of no help.&amp;nbsp; Here is the solution I came up with:
&lt;/p&gt;
&lt;div&gt;
&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ChangeNotifier
: IDisposable&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;{&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    LdapConnection _connection;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    HashSet&amp;lt;IAsyncResult&amp;gt; _results = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HashSet&amp;lt;IAsyncResult&amp;gt;();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ChangeNotifier(LdapConnection
connection)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        _connection = connection;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        _connection.AutoBind = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Register(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; dn,
SearchScope scope)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        SearchRequest request = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SearchRequest(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            dn, &lt;span style="color: #008000"&gt;//root
the search here&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            &lt;span style="color: #006080"&gt;"(objectClass=*)"&lt;/span&gt;, &lt;span style="color: #008000"&gt;//very
inclusive&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            scope, &lt;span style="color: #008000"&gt;//any
scope works&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; &lt;span style="color: #008000"&gt;//we
are interested in all attributes&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            );&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #008000"&gt;//register
our search&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        request.Controls.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; DirectoryNotificationControl());&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        &lt;span style="color: #008000"&gt;//we
will send this async and register our callback&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #008000"&gt;//note
how we would like to have partial results&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        IAsyncResult result = _connection.BeginSendRequest(&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            request,&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            TimeSpan.FromDays(1), &lt;span style="color: #008000"&gt;//set
timeout to a day...&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            PartialResultProcessing.ReturnPartialResultsAndNotifyCallback,&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            Notify,&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            request&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            );&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        &lt;span style="color: #008000"&gt;//store
the hash for disposal later&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        _results.Add(result);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Notify(IAsyncResult
result)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        &lt;span style="color: #008000"&gt;//since
our search is long running, we don't want to use EndSendRequest&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        PartialResultsCollection prc = _connection.GetPartialResults(result);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (SearchResultEntry
entry &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; prc)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            OnObjectChanged(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ObjectChangedEventArgs(entry));&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; OnObjectChanged(ObjectChangedEventArgs
args)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (ObjectChanged
!= &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            ObjectChanged(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;,
args);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;event&lt;/span&gt; EventHandler&amp;lt;ObjectChangedEventArgs&amp;gt;
ObjectChanged;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;span style="color: #cc6633"&gt;#region&lt;/span&gt; IDisposable
Members&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Dispose()&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var
result &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; _results)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            &lt;span style="color: #008000"&gt;//end
each async search&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            _connection.Abort(result);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    &lt;span style="color: #cc6633"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;}&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ObjectChangedEventArgs
: EventArgs&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;{&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ObjectChangedEventArgs(SearchResultEntry
entry)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        Result = entry;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; SearchResultEntry
Result { get; set;}&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
It is a relatively simple class that you can use to register searches.&amp;nbsp; The trick
is using the GetPartialResults method in the callback method to get only the change
that has just occurred.&amp;nbsp; I have also included the very simplified EventArgs class
I am using to pass results back.&amp;nbsp; Note, I am not doing anything about threading
here and I don't have any error handling (this is just a sample).&amp;nbsp; You can consume
this class like so:
&lt;/p&gt;
&lt;div&gt;
&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Main(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[]
args)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;{&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (LdapConnection
connect = CreateConnection(&lt;span style="color: #006080"&gt;"localhost"&lt;/span&gt;))&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (ChangeNotifier
notifier = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ChangeNotifier(connect))&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            &lt;span style="color: #008000"&gt;//register
some objects for notifications (limit 5)&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            notifier.Register(&lt;span style="color: #006080"&gt;"dc=dunnry,dc=net"&lt;/span&gt;,
SearchScope.OneLevel);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            notifier.Register(&lt;span style="color: #006080"&gt;"cn=testuser1,ou=users,dc=dunnry,dc=net"&lt;/span&gt;,
SearchScope.Base);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            notifier.ObjectChanged += &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; EventHandler&amp;lt;ObjectChangedEventArgs&amp;gt;(notifier_ObjectChanged);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            Console.WriteLine(&lt;span style="color: #006080"&gt;"Waiting
for changes..."&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            Console.WriteLine();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            Console.ReadLine();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;}&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; notifier_ObjectChanged(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender,
ObjectChangedEventArgs e)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;{&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    Console.WriteLine(e.Result.DistinguishedName);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; attrib &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; e.Result.Attributes.AttributeNames)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var
item &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; e.Result.Attributes[attrib].GetValues(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;)))&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            Console.WriteLine(&lt;span style="color: #006080"&gt;"\t{0}:
{1}"&lt;/span&gt;, attrib, item);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    Console.WriteLine();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    Console.WriteLine(&lt;span style="color: #006080"&gt;"===================="&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    Console.WriteLine();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
And there you have it... change notifications in .NET.&amp;nbsp; You can also &lt;a href="http://cid-4225352e17899c6d.skydrive.live.com/self.aspx/Public/ChangeNotifications.zip"&gt;download
my project file&lt;/a&gt; for Visual Studio 2008.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=b1e8405e-8e34-4692-83bf-10fa2e69e6c4" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,b1e8405e-8e34-4692-83bf-10fa2e69e6c4.aspx</comments>
      <category>.NET</category>
      <category>Active Directory</category>
      <category>ADAM</category>
      <category>ADSI</category>
      <category>LDAP</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=d29c54e5-8dd0-4779-96c0-40c87f07e500</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,d29c54e5-8dd0-4779-96c0-40c87f07e500.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,d29c54e5-8dd0-4779-96c0-40c87f07e500.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=d29c54e5-8dd0-4779-96c0-40c87f07e500</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
A question came up the other day on how to get LINQ to SQL to participate in using
the SQL Notification Services.  Of course, I didn't know, but Mike Pizzo from
the ADO.NET team was kind enough to answer.  I figured it must be possible, and
sure enough, it is.  Essentially, you have to create a SQL dependency context,
which is very similar to a transaction context.  Any code that participates within
that context will automatically be associated with the SQLDependency.  Create
the dependency first, before any LINQ (or other data access technology).  Here
is the relevant code (note: this code is not optimized, so you might want to do things
like change the SQLDependency to static or pass it in so it won't be garbage collected).
</p>
        <p>
          <!--
{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red0\green128\blue0;\red163\green21\blue21;}??\fs20     \cf3 static\cf0  \cf3 class\cf0  \cf4 GlobalNotifications\par ??\cf0     \{\par ??        \cf3 public\cf0  \cf3 static\cf0  \cf3 event\cf0  OnChangeEventHandler OnChange;\par ??\par ??        \cf3 public\cf0  \cf3 static\cf0  \cf3 void\cf0  InitializeNotifications(\cf3 string\cf0  connectString)\par ??        \{\par ??            \cf5 // Initialize notifications\par ??\cf0             SqlDependency.Start(connectString);\par ??            \cf5 // Create and register a new dependency\par ??\cf0             SqlDependency dependency = \cf3 new\cf0  SqlDependency();\par ??            dependency.OnChange += \cf3 new\cf0  OnChangeEventHandler(NotificationCallback);\par ??            System.Runtime.Remoting.Messaging.\cf4 CallContext\cf0 .SetData(\cf6 "MS.SqlDependencyCookie"\cf0 , dependency.Id);\par ??        \}\par ??\par ??        \cf3 internal\cf0  \cf3 static\cf0  \cf3 void\cf0  NotificationCallback(\cf3 object\cf0  o, SqlNotificationEventArgs args)\par ??        \{\par ??            OnChange.Invoke(o, args);\par ??        \}\par ??    \}}
-->
        </p>
        <div style="font-size: 10pt; background: white; color: black; font-family: consolas">
          <p style="margin: 0px">
    <span style="color: blue">static</span><span style="color: blue">class</span><span style="color: #2b91af">GlobalNotifications</span></p>
          <p style="margin: 0px">
    {
</p>
          <p style="margin: 0px">
        <span style="color: blue">public</span><span style="color: blue">static</span><span style="color: blue">event</span> OnChangeEventHandler
OnChange;
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
        <span style="color: blue">public</span><span style="color: blue">static</span><span style="color: blue">void</span> InitializeNotifications(<span style="color: blue">string</span> connectString)
</p>
          <p style="margin: 0px">
        {
</p>
          <p style="margin: 0px">
            <span style="color: green">//
Initialize notifications</span></p>
          <p style="margin: 0px">
            SqlDependency.Start(connectString);
</p>
          <p style="margin: 0px">
            <span style="color: green">//
Create and register a new dependency</span></p>
          <p style="margin: 0px">
            SqlDependency dependency
= <span style="color: blue">new</span> SqlDependency();
</p>
          <p style="margin: 0px">
            dependency.OnChange += <span style="color: blue">new</span> OnChangeEventHandler(NotificationCallback);
</p>
          <p style="margin: 0px">
            System.Runtime.Remoting.Messaging.<span style="color: #2b91af">CallContext</span>.SetData(<span style="color: #a31515">"MS.SqlDependencyCookie"</span>,
dependency.Id);
</p>
          <p style="margin: 0px">
        }
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
        <span style="color: blue">internal</span><span style="color: blue">static</span><span style="color: blue">void</span> NotificationCallback(<span style="color: blue">object</span> o,
SqlNotificationEventArgs args)
</p>
          <p style="margin: 0px">
        {
</p>
          <p style="margin: 0px">
            OnChange.Invoke(o, args);
</p>
          <p style="margin: 0px">
        }
</p>
          <p style="margin: 0px">
    }
</p>
        </div>
        <p>
There is also one major caveat to using this with LINQ: Beware of complex queries
that can be easily generated using LINQ.  The Query Processor will invalidate
the command and fire an error event saying it was too complex.  Since you can
easily generate lots of complex queries using LINQ (part of its power really), you
need to really be cognizant of this limitation.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=d29c54e5-8dd0-4779-96c0-40c87f07e500" />
      </body>
      <title>Using SQLDependency objects with LINQ</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,d29c54e5-8dd0-4779-96c0-40c87f07e500.aspx</guid>
      <link>http://dunnry.com/blog/2007/09/14/UsingSQLDependencyObjectsWithLINQ.aspx</link>
      <pubDate>Fri, 14 Sep 2007 20:24:19 GMT</pubDate>
      <description>&lt;p&gt;
A question came up the other day on how to get LINQ to SQL to participate in using
the SQL Notification Services.&amp;nbsp; Of course, I didn't know, but Mike Pizzo from
the ADO.NET team was kind enough to answer.&amp;nbsp; I figured it must be possible, and
sure enough, it is.&amp;nbsp; Essentially, you have to create a SQL dependency context,
which is very similar to a transaction context.&amp;nbsp; Any code that participates within
that context will automatically be associated with the SQLDependency.&amp;nbsp; Create
the dependency first, before any LINQ (or other data access technology).&amp;nbsp; Here
is the relevant code (note: this code is not optimized, so you might want to do things
like change the SQLDependency to static or pass it in so it won't be garbage collected).
&lt;/p&gt;
&lt;p&gt;
&lt;!--
{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red0\green128\blue0;\red163\green21\blue21;}??\fs20     \cf3 static\cf0  \cf3 class\cf0  \cf4 GlobalNotifications\par ??\cf0     \{\par ??        \cf3 public\cf0  \cf3 static\cf0  \cf3 event\cf0  OnChangeEventHandler OnChange;\par ??\par ??        \cf3 public\cf0  \cf3 static\cf0  \cf3 void\cf0  InitializeNotifications(\cf3 string\cf0  connectString)\par ??        \{\par ??            \cf5 // Initialize notifications\par ??\cf0             SqlDependency.Start(connectString);\par ??            \cf5 // Create and register a new dependency\par ??\cf0             SqlDependency dependency = \cf3 new\cf0  SqlDependency();\par ??            dependency.OnChange += \cf3 new\cf0  OnChangeEventHandler(NotificationCallback);\par ??            System.Runtime.Remoting.Messaging.\cf4 CallContext\cf0 .SetData(\cf6 "MS.SqlDependencyCookie"\cf0 , dependency.Id);\par ??        \}\par ??\par ??        \cf3 internal\cf0  \cf3 static\cf0  \cf3 void\cf0  NotificationCallback(\cf3 object\cf0  o, SqlNotificationEventArgs args)\par ??        \{\par ??            OnChange.Invoke(o, args);\par ??        \}\par ??    \}}
--&gt;
&lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas"&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af"&gt;GlobalNotifications&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;event&lt;/span&gt; OnChangeEventHandler
OnChange;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; InitializeNotifications(&lt;span style="color: blue"&gt;string&lt;/span&gt; connectString)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green"&gt;//
Initialize notifications&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SqlDependency.Start(connectString);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green"&gt;//
Create and register a new dependency&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SqlDependency dependency
= &lt;span style="color: blue"&gt;new&lt;/span&gt; SqlDependency();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; dependency.OnChange += &lt;span style="color: blue"&gt;new&lt;/span&gt; OnChangeEventHandler(NotificationCallback);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; System.Runtime.Remoting.Messaging.&lt;span style="color: #2b91af"&gt;CallContext&lt;/span&gt;.SetData(&lt;span style="color: #a31515"&gt;"MS.SqlDependencyCookie"&lt;/span&gt;,
dependency.Id);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;internal&lt;/span&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; NotificationCallback(&lt;span style="color: blue"&gt;object&lt;/span&gt; o,
SqlNotificationEventArgs args)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; OnChange.Invoke(o, args);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
There is also one major caveat to using this with LINQ: Beware of complex queries
that can be easily generated using LINQ.&amp;nbsp; The Query Processor will invalidate
the command and fire an error event saying it was too complex.&amp;nbsp; Since you can
easily generate lots of complex queries using LINQ (part of its power really), you
need to really be cognizant of this limitation.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=d29c54e5-8dd0-4779-96c0-40c87f07e500" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,d29c54e5-8dd0-4779-96c0-40c87f07e500.aspx</comments>
      <category>.NET</category>
      <category>LINQ</category>
      <category>Tips</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=ebbcda67-a1ac-45fa-9aca-1b6de2f7a058</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,ebbcda67-a1ac-45fa-9aca-1b6de2f7a058.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,ebbcda67-a1ac-45fa-9aca-1b6de2f7a058.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=ebbcda67-a1ac-45fa-9aca-1b6de2f7a058</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Link pair attributes in Active Directory and ADAM can be quite big.  I don't
know the official limit, but needless to say, for practical purposes you can assume
they are quite large indeed.  By default, AD and ADAM will not return the entire
attribute if it contains more than a certain number of values (1000 for Windows 2000
and 1500 for Windows 2003+ by default).  As such, if you truly want robust code,
you need to always use what is called range retrieval for link value paired attributes.
</p>
        <p>
Range retrieval is a process similar to paging in directory services, whereby you
ask the directory for a certain range of particular attribute.  You know that
you are using range retrieval when you see the attribute being requested in the following
format:
</p>
        <p>
"[attribute];range=[start]-[end]"
</p>
        <p>
As an example, in the case of the 'member' attribute, you might ask for the first
1500 values like so:
</p>
        <p>
"member;range=0-1499"
</p>
        <p>
Notice, it is zero based so you need to take this into account.  The general
algorithm as such is:
</p>
        <ol>
          <li>
Ask for as big as you can get.  This means use the "*" for the ending range to
ask for it all. 
</li>
          <li>
The directory will respond with either the actual max value (some integer), or with
a "*" indicating you got everything.  If you got everything, you are done. 
</li>
          <li>
If not, using the max value now as your step, repeatedly ask for larger and larger
values inside a loop until the directory responds with a "*" as the end range.</li>
        </ol>
        <p>
We covered how to use range retrieval in SDS in <a href="http://www.amazon.com/exec/obidos/redirect?link_code=as2&amp;path=ASIN/0321350170&amp;tag=extemporaneou-20&amp;camp=1789&amp;creative=9325">our
book</a>, and you can download sample code that shows how from the <a href="http://directoryprogramming.net">book's
website</a>.  What we didn't cover was how to do it in SDS.P.
</p>
        <p>
SDS.P is a layer closer the the metal than our ADSI based System.DirectoryServices
(SDS).  As such, if you are expected to do range retrieval for SDS, you can be
assured that you need to do it for SDS.P as well.  Adopting the code SDS, you
get something like this (but modified to some extent):
</p>
        <!--
{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Lucida Console;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red43\green145\blue175;\red163\green21\blue21;\red0\green128\blue0;}??\fs20 \cf1 static\cf0  \cf4 List\cf0 &lt;\cf1 string\cf0 &gt; RangeRetrieve(\par ??    LdapConnection connect, \cf1 string\cf0  dn, \cf1 string\cf0  attribute)\par ??\{\par ??    \cf1 int\cf0  idx = 0;\par ??    \cf1 int\cf0  step = 0;\par ??    \cf4 List\cf0 &lt;\cf1 string\cf0 &gt; list = \cf1 new\cf0  \cf4 List\cf0 &lt;\cf1 string\cf0 &gt;();\par ??\par ??    \cf1 string\cf0  range = \cf4 String\cf0 .Format(\par ??       \cf5 "\{0\};range=\{\{0\}\}-\{\{1\}\}"\cf0 ,\par ??       attribute\par ??       );\par ??\par ??    \cf1 string\cf0  currentRange = \cf4 String\cf0 .Format(range, idx, \cf5 "*"\cf0 );\par ??\par ??    SearchRequest request = \cf1 new\cf0  SearchRequest(\par ??        dn,\par ??        \cf4 String\cf0 .Format(\cf5 "(\{0\}=*)"\cf0 , attribute),\par ??        SearchScope.Base,\par ??        \cf1 new\cf0  \cf1 string\cf0 [] \{ currentRange \}\par ??        );\par ??\par ??    SearchResultEntry entry = \cf1 null\cf0 ;\par ??    \cf1 bool\cf0  lastSearch = \cf1 false\cf0 ;\par ??\par ??    \cf1 while\cf0  (\cf1 true\cf0 )\par ??    \{\par ??        SearchResponse response = \par ??            (SearchResponse)connect.SendRequest(request);\par ??\par ??        \cf1 if\cf0  (response.Entries.Count == 1) \cf6 //should only be one\par ??\cf0         \{\par ??            entry = response.Entries[0];\par ??\par ??            \cf6 //this might be optimized to find full step or just use 1000 for\par ??\cf0             \cf6 //compromise\par ??\cf0             \cf1 foreach\cf0  (\cf1 string\cf0  attrib \cf1 in\cf0  entry.Attributes.AttributeNames)\par ??            \{\par ??                currentRange = attrib;\par ??                lastSearch = currentRange.IndexOf(\cf5 "*"\cf0 , 0) &gt; 0;\par ??                step = entry.Attributes[currentRange].Count;\par ??            \}\par ??\par ??            \cf1 foreach\cf0  (\cf1 string\cf0  member \cf1 in\cf0  \par ??                entry.Attributes[currentRange].GetValues(\cf1 typeof\cf0 (\cf1 string\cf0 )))\par ??            \{\par ??                list.Add(member);\par ??                idx++;\par ??            \}\par ??\par ??            \cf1 if\cf0  (lastSearch)\par ??                \cf1 break\cf0 ;\par ??\par ??            currentRange = \cf4 String\cf0 .Format(range, idx, (idx + step));\par ??\par ??            request.Attributes.Clear();\par ??            request.Attributes.Add(currentRange);\par ??\par ??        \}\par ??        \cf1 else\par ??\cf0             \cf1 break\cf0 ;\par ??\par ??    \}\par ??    \cf1 return\cf0  list;\par ??\}}
-->
        <div style="font-size: 10pt; background: white; color: black; font-family: lucida console">
          <p style="margin: 0px">
            <span style="color: blue">static</span>
            <span style="color: #2b91af">List</span>&lt;<span style="color: blue">string</span>&gt;
RangeRetrieve(
</p>
          <p style="margin: 0px">
    LdapConnection connect, <span style="color: blue">string</span> dn, <span style="color: blue">string</span> attribute)
</p>
          <p style="margin: 0px">
{
</p>
          <p style="margin: 0px">
    <span style="color: blue">int</span> idx = 0;
</p>
          <p style="margin: 0px">
    <span style="color: blue">int</span> step = 0;
</p>
          <p style="margin: 0px">
    <span style="color: #2b91af">List</span>&lt;<span style="color: blue">string</span>&gt;
list = <span style="color: blue">new</span><span style="color: #2b91af">List</span>&lt;<span style="color: blue">string</span>&gt;();
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
    <span style="color: blue">string</span> range = <span style="color: #2b91af">String</span>.Format(
</p>
          <p style="margin: 0px">
       <span style="color: #a31515">"{0};range={{0}}-{{1}}"</span>,
</p>
          <p style="margin: 0px">
       attribute
</p>
          <p style="margin: 0px">
       );
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
    <span style="color: blue">string</span> currentRange = <span style="color: #2b91af">String</span>.Format(range,
idx, <span style="color: #a31515">"*"</span>);
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
    SearchRequest request = <span style="color: blue">new</span> SearchRequest(
</p>
          <p style="margin: 0px">
        dn,
</p>
          <p style="margin: 0px">
        <span style="color: #2b91af">String</span>.Format(<span style="color: #a31515">"({0}=*)"</span>,
attribute),
</p>
          <p style="margin: 0px">
        SearchScope.Base,
</p>
          <p style="margin: 0px">
        <span style="color: blue">new</span><span style="color: blue">string</span>[]
{ currentRange }
</p>
          <p style="margin: 0px">
        );
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
    SearchResultEntry entry = <span style="color: blue">null</span>;
</p>
          <p style="margin: 0px">
    <span style="color: blue">bool</span> lastSearch = <span style="color: blue">false</span>;
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
    <span style="color: blue">while</span> (<span style="color: blue">true</span>)
</p>
          <p style="margin: 0px">
    {
</p>
          <p style="margin: 0px">
        SearchResponse response = 
</p>
          <p style="margin: 0px">
            (SearchResponse)connect.SendRequest(request);
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
        <span style="color: blue">if</span> (response.Entries.Count
== 1) <span style="color: green">//should only be one</span></p>
          <p style="margin: 0px">
        {
</p>
          <p style="margin: 0px">
            entry = response.Entries[0];
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
            <span style="color: green">//this
might be optimized to find full step or just use 1000 for</span></p>
          <p style="margin: 0px">
            <span style="color: green">//compromise</span></p>
          <p style="margin: 0px">
            <span style="color: blue">foreach</span> (<span style="color: blue">string</span> attrib <span style="color: blue">in</span> entry.Attributes.AttributeNames)
</p>
          <p style="margin: 0px">
            {
</p>
          <p style="margin: 0px">
                currentRange
= attrib;
</p>
          <p style="margin: 0px">
                lastSearch
= currentRange.IndexOf(<span style="color: #a31515">"*"</span>, 0) &gt; 0;
</p>
          <p style="margin: 0px">
                step =
entry.Attributes[currentRange].Count;
</p>
          <p style="margin: 0px">
            }
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
            <span style="color: blue">foreach</span> (<span style="color: blue">string</span> member <span style="color: blue">in</span></p>
          <p style="margin: 0px">
                entry.Attributes[currentRange].GetValues(<span style="color: blue">typeof</span>(<span style="color: blue">string</span>)))
</p>
          <p style="margin: 0px">
            {
</p>
          <p style="margin: 0px">
                list.Add(member);
</p>
          <p style="margin: 0px">
                idx++;
</p>
          <p style="margin: 0px">
            }
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
            <span style="color: blue">if</span> (lastSearch)
</p>
          <p style="margin: 0px">
                <span style="color: blue">break</span>;
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
            currentRange = <span style="color: #2b91af">String</span>.Format(range,
idx, (idx + step));
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
            request.Attributes.Clear();
</p>
          <p style="margin: 0px">
            request.Attributes.Add(currentRange);
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
        }
</p>
          <p style="margin: 0px">
        <span style="color: blue">else</span></p>
          <p style="margin: 0px">
            <span style="color: blue">break</span>;
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
    }
</p>
          <p style="margin: 0px">
    <span style="color: blue">return</span> list;
</p>
          <p style="margin: 0px">
}
</p>
        </div>
        <p>
Happy coding... of course, if you are clever you will realize you can avoid all this
range retrieval mess by using an attribute scope query (ASQ). :)
</p>
        <p>
*edit: tried to fix the style for code to render in Google Reader correctly
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=ebbcda67-a1ac-45fa-9aca-1b6de2f7a058" />
      </body>
      <title>Range Retrieval using System.DirectoryServices.Protocols</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,ebbcda67-a1ac-45fa-9aca-1b6de2f7a058.aspx</guid>
      <link>http://dunnry.com/blog/2007/08/10/RangeRetrievalUsingSystemDirectoryServicesProtocols.aspx</link>
      <pubDate>Fri, 10 Aug 2007 20:53:21 GMT</pubDate>
      <description>&lt;p&gt;
Link pair attributes in Active Directory and ADAM can be quite big.&amp;nbsp; I don't
know the official limit, but needless to say, for practical purposes you can assume
they are quite large indeed.&amp;nbsp; By default, AD and ADAM will not return the entire
attribute if it contains more than a certain number of values (1000 for Windows 2000
and 1500 for Windows 2003+ by default).&amp;nbsp; As such, if you truly want robust code,
you need to always use what is called range retrieval for link value paired attributes.
&lt;/p&gt;
&lt;p&gt;
Range retrieval is a process similar to paging in directory services, whereby you
ask the directory for a certain range of particular attribute.&amp;nbsp; You know that
you are using range retrieval when you see the attribute being requested in the following
format:
&lt;/p&gt;
&lt;p&gt;
"[attribute];range=[start]-[end]"
&lt;/p&gt;
&lt;p&gt;
As an example, in the case of the 'member' attribute, you might ask for the first
1500 values like so:
&lt;/p&gt;
&lt;p&gt;
"member;range=0-1499"
&lt;/p&gt;
&lt;p&gt;
Notice, it is zero based so you need to take this into account.&amp;nbsp; The general
algorithm as such is:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Ask for as big as you can get.&amp;nbsp; This means use the "*" for the ending range to
ask for it all. 
&lt;li&gt;
The directory will respond with either the actual max value (some integer), or with
a "*" indicating you got everything.&amp;nbsp; If you got everything, you are done. 
&lt;li&gt;
If not, using the max value now as your step, repeatedly ask for larger and larger
values inside a loop until the directory responds with a "*" as the end range.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
We covered how to use range retrieval in SDS in &lt;a href="http://www.amazon.com/exec/obidos/redirect?link_code=as2&amp;amp;path=ASIN/0321350170&amp;amp;tag=extemporaneou-20&amp;amp;camp=1789&amp;amp;creative=9325"&gt;our
book&lt;/a&gt;, and you can download sample code that shows how from the &lt;a href="http://directoryprogramming.net"&gt;book's
website&lt;/a&gt;.&amp;nbsp; What we didn't cover was how to do it in SDS.P.
&lt;/p&gt;
&lt;p&gt;
SDS.P is a layer closer the the metal than our ADSI based System.DirectoryServices
(SDS).&amp;nbsp; As such, if you are expected to do range retrieval for SDS, you can be
assured that you need to do it for SDS.P as well.&amp;nbsp; Adopting the code SDS, you
get something like this (but modified to some extent):
&lt;/p&gt;
&lt;!--
{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Lucida Console;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red43\green145\blue175;\red163\green21\blue21;\red0\green128\blue0;}??\fs20 \cf1 static\cf0  \cf4 List\cf0 &amp;lt;\cf1 string\cf0 &amp;gt; RangeRetrieve(\par ??    LdapConnection connect, \cf1 string\cf0  dn, \cf1 string\cf0  attribute)\par ??\{\par ??    \cf1 int\cf0  idx = 0;\par ??    \cf1 int\cf0  step = 0;\par ??    \cf4 List\cf0 &amp;lt;\cf1 string\cf0 &amp;gt; list = \cf1 new\cf0  \cf4 List\cf0 &amp;lt;\cf1 string\cf0 &amp;gt;();\par ??\par ??    \cf1 string\cf0  range = \cf4 String\cf0 .Format(\par ??       \cf5 "\{0\};range=\{\{0\}\}-\{\{1\}\}"\cf0 ,\par ??       attribute\par ??       );\par ??\par ??    \cf1 string\cf0  currentRange = \cf4 String\cf0 .Format(range, idx, \cf5 "*"\cf0 );\par ??\par ??    SearchRequest request = \cf1 new\cf0  SearchRequest(\par ??        dn,\par ??        \cf4 String\cf0 .Format(\cf5 "(\{0\}=*)"\cf0 , attribute),\par ??        SearchScope.Base,\par ??        \cf1 new\cf0  \cf1 string\cf0 [] \{ currentRange \}\par ??        );\par ??\par ??    SearchResultEntry entry = \cf1 null\cf0 ;\par ??    \cf1 bool\cf0  lastSearch = \cf1 false\cf0 ;\par ??\par ??    \cf1 while\cf0  (\cf1 true\cf0 )\par ??    \{\par ??        SearchResponse response = \par ??            (SearchResponse)connect.SendRequest(request);\par ??\par ??        \cf1 if\cf0  (response.Entries.Count == 1) \cf6 //should only be one\par ??\cf0         \{\par ??            entry = response.Entries[0];\par ??\par ??            \cf6 //this might be optimized to find full step or just use 1000 for\par ??\cf0             \cf6 //compromise\par ??\cf0             \cf1 foreach\cf0  (\cf1 string\cf0  attrib \cf1 in\cf0  entry.Attributes.AttributeNames)\par ??            \{\par ??                currentRange = attrib;\par ??                lastSearch = currentRange.IndexOf(\cf5 "*"\cf0 , 0) &amp;gt; 0;\par ??                step = entry.Attributes[currentRange].Count;\par ??            \}\par ??\par ??            \cf1 foreach\cf0  (\cf1 string\cf0  member \cf1 in\cf0  \par ??                entry.Attributes[currentRange].GetValues(\cf1 typeof\cf0 (\cf1 string\cf0 )))\par ??            \{\par ??                list.Add(member);\par ??                idx++;\par ??            \}\par ??\par ??            \cf1 if\cf0  (lastSearch)\par ??                \cf1 break\cf0 ;\par ??\par ??            currentRange = \cf4 String\cf0 .Format(range, idx, (idx + step));\par ??\par ??            request.Attributes.Clear();\par ??            request.Attributes.Add(currentRange);\par ??\par ??        \}\par ??        \cf1 else\par ??\cf0             \cf1 break\cf0 ;\par ??\par ??    \}\par ??    \cf1 return\cf0  list;\par ??\}}
--&gt;
&lt;div style="font-size: 10pt; background: white; color: black; font-family: lucida console"&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;
RangeRetrieve(
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; LdapConnection connect, &lt;span style="color: blue"&gt;string&lt;/span&gt; dn, &lt;span style="color: blue"&gt;string&lt;/span&gt; attribute)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;int&lt;/span&gt; idx = 0;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;int&lt;/span&gt; step = 0;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;
list = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;string&lt;/span&gt; range = &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="color: #a31515"&gt;"{0};range={{0}}-{{1}}"&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; attribute
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; );
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;string&lt;/span&gt; currentRange = &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(range,
idx, &lt;span style="color: #a31515"&gt;"*"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; SearchRequest request = &lt;span style="color: blue"&gt;new&lt;/span&gt; SearchRequest(
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; dn,
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(&lt;span style="color: #a31515"&gt;"({0}=*)"&lt;/span&gt;,
attribute),
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SearchScope.Base,
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: blue"&gt;string&lt;/span&gt;[]
{ currentRange }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; );
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; SearchResultEntry entry = &lt;span style="color: blue"&gt;null&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;bool&lt;/span&gt; lastSearch = &lt;span style="color: blue"&gt;false&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;while&lt;/span&gt; (&lt;span style="color: blue"&gt;true&lt;/span&gt;)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SearchResponse response = 
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; (SearchResponse)connect.SendRequest(request);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;if&lt;/span&gt; (response.Entries.Count
== 1) &lt;span style="color: green"&gt;//should only be one&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; entry = response.Entries[0];
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green"&gt;//this
might be optimized to find full step or just use 1000 for&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green"&gt;//compromise&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;foreach&lt;/span&gt; (&lt;span style="color: blue"&gt;string&lt;/span&gt; attrib &lt;span style="color: blue"&gt;in&lt;/span&gt; entry.Attributes.AttributeNames)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; currentRange
= attrib;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; lastSearch
= currentRange.IndexOf(&lt;span style="color: #a31515"&gt;"*"&lt;/span&gt;, 0) &amp;gt; 0;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; step =
entry.Attributes[currentRange].Count;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;foreach&lt;/span&gt; (&lt;span style="color: blue"&gt;string&lt;/span&gt; member &lt;span style="color: blue"&gt;in&lt;/span&gt; 
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; entry.Attributes[currentRange].GetValues(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: blue"&gt;string&lt;/span&gt;)))
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; list.Add(member);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; idx++;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;if&lt;/span&gt; (lastSearch)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;break&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; currentRange = &lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Format(range,
idx, (idx + step));
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; request.Attributes.Clear();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; request.Attributes.Add(currentRange);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;else&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;break&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;return&lt;/span&gt; list;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Happy coding... of course, if you are clever you will realize you can avoid all this
range retrieval mess by using an attribute scope query (ASQ). :)
&lt;/p&gt;
&lt;p&gt;
*edit: tried to fix the style for code to render in Google Reader correctly
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=ebbcda67-a1ac-45fa-9aca-1b6de2f7a058" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,ebbcda67-a1ac-45fa-9aca-1b6de2f7a058.aspx</comments>
      <category>.NET</category>
      <category>Active Directory</category>
      <category>ADAM</category>
      <category>Groups</category>
      <category>LDAP</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=54fbb420-9958-48e8-9d0f-e6f0f76b512d</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,54fbb420-9958-48e8-9d0f-e6f0f76b512d.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,54fbb420-9958-48e8-9d0f-e6f0f76b512d.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=54fbb420-9958-48e8-9d0f-e6f0f76b512d</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I have <a href="http://dunnry.com/blog/CategoryView,category,Groups.aspx">previously
covered</a> pretty extensively the options for getting a user's group membership in
Active Directory or ADAM (soon to be Active Directory LDS (Lightweight Directory Services))
here on the blog, in the <a href="http://directoryprogramming.net/forums/9/ShowForum.aspx">forum</a>,
and in <a href="http://www.amazon.com/exec/obidos/redirect?link_code=as2&amp;path=ASIN/0321350170&amp;tag=extemporaneou-20&amp;camp=1789&amp;creative=9325">the
book</a>.  However, there is a new option for users of .NET 3.5 that should be
of interest.
</p>
        <p>
The Directory Services group at Microsoft has released in beta form a new API for
dealing with a lot of the common things we need to do with users, groups, and computers
in Active Directory, ADAM, and the local machine.  This API is called System.DirectoryServices.AccountManagement
(or SDS.AM).  Here is a simple example of how to get a users groups (including
nested, and primary): 
</p>
        <pre class="code">
          <span style="color: rgb(0,0,255)">static</span>
          <span style="color: rgb(0,0,255)">void</span> Main(<span style="color: rgb(0,0,255)">string</span>[]
args) { <span style="color: rgb(43,145,175)">PrincipalContext</span> ctx = <span style="color: rgb(0,0,255)">new</span><span style="color: rgb(43,145,175)">PrincipalContext</span>(<span style="color: rgb(43,145,175)">ContextType</span>.Domain); <span style="color: rgb(0,0,255)">using</span> (ctx)
{ <span style="color: rgb(43,145,175)">Principal</span> p = <span style="color: rgb(43,145,175)">Principal</span>.FindByIdentity(ctx, <span style="color: rgb(163,21,21)">"ryandunn"</span>); <span style="color: rgb(0,0,255)">using</span> (p)
{ <span style="color: rgb(0,0,255)">var</span> groups = p.GetGroups(); <span style="color: rgb(0,0,255)">using</span> (groups)
{ <span style="color: rgb(0,0,255)">foreach</span> (<span style="color: rgb(43,145,175)">Principal</span> group <span style="color: rgb(0,0,255)">in</span> groups)
{ <span style="color: rgb(43,145,175)">Console</span>.WriteLine(group.SamAccountName
+ <span style="color: rgb(163,21,21)">"-"</span> + group.DisplayName); } } } } <span style="color: rgb(43,145,175)">Console</span>.ReadLine();
}</pre>
        <p>
That's not too bad - in fact, it looks worse than it is because I am trying to make
sure everything is wrapped in a 'using' statement where necessary.  The equivalent
code to do this would be many times more (using DsCrackNames or LDAP searches) and
would yield far less information being returned (just the DN in most cases). 
</p>
        <p>
Over the next few weeks and months, I intend to dig more deeply into this namespace
and put some samples up here for everyone.  This is just a taste for now, but
it should show you how powerful this namespace really is.
</p>
        <p>
 *Updated to fix CSS renderings in Google Reader
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=54fbb420-9958-48e8-9d0f-e6f0f76b512d" />
      </body>
      <title>Getting Active Directory Group Membership in .NET 3.5</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,54fbb420-9958-48e8-9d0f-e6f0f76b512d.aspx</guid>
      <link>http://dunnry.com/blog/2007/08/01/GettingActiveDirectoryGroupMembershipInNET35.aspx</link>
      <pubDate>Wed, 01 Aug 2007 20:33:16 GMT</pubDate>
      <description>&lt;p&gt;
I have &lt;a href="http://dunnry.com/blog/CategoryView,category,Groups.aspx"&gt;previously
covered&lt;/a&gt; pretty extensively the options for getting a user's group membership in
Active Directory or ADAM (soon to be Active Directory LDS (Lightweight Directory Services))
here on the blog, in the &lt;a href="http://directoryprogramming.net/forums/9/ShowForum.aspx"&gt;forum&lt;/a&gt;,
and in &lt;a href="http://www.amazon.com/exec/obidos/redirect?link_code=as2&amp;amp;path=ASIN/0321350170&amp;amp;tag=extemporaneou-20&amp;amp;camp=1789&amp;amp;creative=9325"&gt;the
book&lt;/a&gt;.&amp;nbsp; However, there is a new option for users of .NET 3.5 that should be
of interest.
&lt;/p&gt;
&lt;p&gt;
The Directory Services group at Microsoft has released in beta form a new API for
dealing with a lot of the common things we need to do with users, groups, and computers
in Active Directory, ADAM, and the local machine.&amp;nbsp; This API is called System.DirectoryServices.AccountManagement
(or SDS.AM).&amp;nbsp; Here is a simple example of how to get a users groups (including
nested, and primary): &lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; Main(&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt;[]
args) { &lt;span style="color: rgb(43,145,175)"&gt;PrincipalContext&lt;/span&gt; ctx = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;PrincipalContext&lt;/span&gt;(&lt;span style="color: rgb(43,145,175)"&gt;ContextType&lt;/span&gt;.Domain); &lt;span style="color: rgb(0,0,255)"&gt;using&lt;/span&gt; (ctx)
{ &lt;span style="color: rgb(43,145,175)"&gt;Principal&lt;/span&gt; p = &lt;span style="color: rgb(43,145,175)"&gt;Principal&lt;/span&gt;.FindByIdentity(ctx, &lt;span style="color: rgb(163,21,21)"&gt;"ryandunn"&lt;/span&gt;); &lt;span style="color: rgb(0,0,255)"&gt;using&lt;/span&gt; (p)
{ &lt;span style="color: rgb(0,0,255)"&gt;var&lt;/span&gt; groups = p.GetGroups(); &lt;span style="color: rgb(0,0,255)"&gt;using&lt;/span&gt; (groups)
{ &lt;span style="color: rgb(0,0,255)"&gt;foreach&lt;/span&gt; (&lt;span style="color: rgb(43,145,175)"&gt;Principal&lt;/span&gt; group &lt;span style="color: rgb(0,0,255)"&gt;in&lt;/span&gt; groups)
{ &lt;span style="color: rgb(43,145,175)"&gt;Console&lt;/span&gt;.WriteLine(group.SamAccountName
+ &lt;span style="color: rgb(163,21,21)"&gt;"-"&lt;/span&gt; + group.DisplayName); } } } } &lt;span style="color: rgb(43,145,175)"&gt;Console&lt;/span&gt;.ReadLine();
}&lt;/pre&gt;
&lt;p&gt;
That's not too bad - in fact, it looks worse than it is because I am trying to make
sure everything is wrapped in a 'using' statement where necessary.&amp;nbsp; The equivalent
code to do this would be many times more (using DsCrackNames or LDAP searches) and
would yield far less information being returned (just the DN in most cases). 
&lt;p&gt;
Over the next few weeks and months, I intend to dig more deeply into this namespace
and put some samples up here for everyone.&amp;nbsp; This is just a taste for now, but
it should show you how powerful this namespace really is.
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;*Updated to fix CSS renderings in Google Reader
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=54fbb420-9958-48e8-9d0f-e6f0f76b512d" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,54fbb420-9958-48e8-9d0f-e6f0f76b512d.aspx</comments>
      <category>.NET</category>
      <category>Active Directory</category>
      <category>ADAM</category>
      <category>ADSI</category>
      <category>DsCrackNames</category>
      <category>Groups</category>
      <category>LDAP</category>
      <category>tokenGroups</category>
      <category>VS.NET</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=7d80160c-6f7f-4865-b0b9-6d181d6a8fdc</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,7d80160c-6f7f-4865-b0b9-6d181d6a8fdc.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,7d80160c-6f7f-4865-b0b9-6d181d6a8fdc.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=7d80160c-6f7f-4865-b0b9-6d181d6a8fdc</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
One of the major changes introduced with IIS7 is the removal of the metabase. 
This probably comes as a great relief to many of the admins and developers that struggled
with coordinating configuration across multiple machines.  Instead of the metabase,
IIS7 has chosen to schematize all the web server settings and host them centrally
in a new XML file called applicationHost.config located at '%windir%\system32\inetsrv\config'.
</p>
        <p>
The schema itself can be found in the 'schema' folder right below the 'config' directory. 
This new centralized configuration file holds all the global default values for IIS7
as well as defines what sites, applications, virtual directories, app pools, etc.
are on the server.
</p>
        <p>
Let's take a look just a couple items I found in my applicationHost.config:
</p>
        <pre class="code">
          <span style="color: rgb(0,0,255)">&lt;</span>
          <span style="color: rgb(163,21,21)">applicationPools</span>
          <span style="color: rgb(0,0,255)">&gt;
&lt;</span>
          <span style="color: rgb(163,21,21)">add</span>
          <span style="color: rgb(0,0,255)">
          </span>
          <span style="color: rgb(255,0,0)">name</span>
          <span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">DefaultAppPool</span>"<span style="color: rgb(0,0,255)"> /&gt;
&lt;</span><span style="color: rgb(163,21,21)">add</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">Classic
.NET AppPool</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">managedPipelineMode</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">Classic</span>"<span style="color: rgb(0,0,255)"> /&gt;
&lt;</span><span style="color: rgb(163,21,21)">applicationPoolDefaults</span><span style="color: rgb(0,0,255)">&gt;
&lt;</span><span style="color: rgb(163,21,21)">processModel</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">identityType</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">NetworkService</span>"<span style="color: rgb(0,0,255)"> /&gt;
&lt;/</span><span style="color: rgb(163,21,21)">applicationPoolDefaults</span><span style="color: rgb(0,0,255)">&gt;
&lt;/</span><span style="color: rgb(163,21,21)">applicationPools</span><span style="color: rgb(0,0,255)">&gt;</span></pre>
        <a href="http://11011.net/software/vspaste">
        </a>
        <p>
Here is the configuration of the application pools on my IIS7 server.  Let's
see what happens if we just edit this directly and add a new application pool.
</p>
        <p>
          <a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/DiscoveringIIS7Schema_D463/AppPool.png" atomicselection="true">
            <img height="196" alt="AppPool" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/DiscoveringIIS7Schema_D463/AppPool_thumb.png" width="525" border="0" />
          </a>
        </p>
        <p>
If we open our new IIS Manager (Start &gt; Run &gt; inetmgr), we can see that this
is all there is to it.
</p>
        <p>
          <a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/DiscoveringIIS7Schema_D463/AppPoolsInManager.png" atomicselection="true">
            <img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="255" alt="AppPoolsInManager" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/DiscoveringIIS7Schema_D463/AppPoolsInManager_thumb.png" width="640" border="0" />
          </a>
        </p>
        <p>
Further poking around will yield lists of sites, applications, and virtual directories
as well - all described neatly in XML format.  Now, how did the IIS team put
all this together?  Were they using their own black box implementation? 
If we inspect the schema, we will find there is no magic here and the IIS team is
leveraging its own schema system for IIS itself.  Opening the "IIS_Schema.xml"
file found in the 'schema' directory shows us the exact settings available for 'applicationPools'.
</p>
        <pre class="code">
          <span style="color: rgb(0,0,255)"> &lt;</span>
          <span style="color: rgb(163,21,21)">sectionSchema</span>
          <span style="color: rgb(0,0,255)">
          </span>
          <span style="color: rgb(255,0,0)">name</span>
          <span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">system.applicationHost/applicationPools</span>"<span style="color: rgb(0,0,255)">&gt;
&lt;</span><span style="color: rgb(163,21,21)">collection</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">addElement</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">add</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">defaultElement</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">applicationPoolDefaults</span>"<span style="color: rgb(0,0,255)">&gt;
&lt;</span><span style="color: rgb(163,21,21)">attribute</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">name</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">type</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">string</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">required</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">true</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">isUniqueKey</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">true</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">validationType</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">applicationPoolName</span>"<span style="color: rgb(0,0,255)"> /&gt;
&lt;</span><span style="color: rgb(163,21,21)">attribute</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">queueLength</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">type</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">uint</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">defaultValue</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">1000</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">validationType</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">integerRange</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">validationParameter</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">10,65535</span>"<span style="color: rgb(0,0,255)">/&gt;
&lt;</span><span style="color: rgb(163,21,21)">attribute</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">autoStart</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">type</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">bool</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">defaultValue</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">true</span>"<span style="color: rgb(0,0,255)"> /&gt;
&lt;</span><span style="color: rgb(163,21,21)">attribute</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">enable32BitAppOnWin64</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">type</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">bool</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">defaultValue</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">false</span>"<span style="color: rgb(0,0,255)"> /&gt;
&lt;</span><span style="color: rgb(163,21,21)">attribute</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">managedRuntimeVersion</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">type</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">string</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">defaultValue</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">v2.0</span>"<span style="color: rgb(0,0,255)"> /&gt;
&lt;</span><span style="color: rgb(163,21,21)">attribute</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">managedPipelineMode</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">type</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">enum</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">defaultValue</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">Integrated</span>"<span style="color: rgb(0,0,255)">&gt;
&lt;</span><span style="color: rgb(163,21,21)">enum</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">Integrated</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">value</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">0</span>"<span style="color: rgb(0,0,255)"> /&gt;
&lt;</span><span style="color: rgb(163,21,21)">enum</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">Classic</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">value</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">1</span>"<span style="color: rgb(0,0,255)"> /&gt;
&lt;/</span><span style="color: rgb(163,21,21)">attribute</span><span style="color: rgb(0,0,255)">&gt;
&lt;</span><span style="color: rgb(163,21,21)">attribute</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">passAnonymousToken</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">type</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">bool</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">defaultValue</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">true</span>"<span style="color: rgb(0,0,255)"> /&gt;
&lt;</span><span style="color: rgb(163,21,21)">element</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">processModel</span>"<span style="color: rgb(0,0,255)">&gt;
&lt;</span><span style="color: rgb(163,21,21)">attribute</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">identityType</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">type</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">enum</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">defaultValue</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">NetworkService</span>"<span style="color: rgb(0,0,255)">&gt;
&lt;</span><span style="color: rgb(163,21,21)">enum</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">LocalSystem</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">value</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">0</span>"<span style="color: rgb(0,0,255)">/&gt;
&lt;</span><span style="color: rgb(163,21,21)">enum</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">LocalService</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">value</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">1</span>"<span style="color: rgb(0,0,255)">/&gt;
&lt;</span><span style="color: rgb(163,21,21)">enum</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">NetworkService</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">value</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">2</span>"<span style="color: rgb(0,0,255)">/&gt;
&lt;</span><span style="color: rgb(163,21,21)">enum</span><span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">name</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">SpecificUser</span>"<span style="color: rgb(0,0,255)"></span><span style="color: rgb(255,0,0)">value</span><span style="color: rgb(0,0,255)">=</span>"<span style="color: rgb(0,0,255)">3</span>"<span style="color: rgb(0,0,255)">/&gt;
&lt;/</span><span style="color: rgb(163,21,21)">attribute</span><span style="color: rgb(0,0,255)">&gt; </span><span style="color: rgb(0,0,255)"> &lt;...SNIP...</span><span style="color: rgb(0,0,255)">&gt;
&lt;/</span><span style="color: rgb(163,21,21)">sectionSchema</span><span style="color: rgb(0,0,255)">&gt;</span></pre>
        <p>
As we can see here, there are some basic typed attributes that describe our application
pool.  They have things like types, default values, and even enumerations with
possible values (managedPipelineMode is one such).  There really is no magic
here.  Someone could very easily write a program that inspected the schema of
IIS7 fully and presented all possible options just by inspecting this schema.
</p>
        <p>
What should immediately come to mind as a developer is, "<strong>how can I leverage
this system</strong>"?  If there is one word that describes IIS7, it is "<strong>Extensible</strong>". 
In my next post, I will show you how to leverage this powerful schema system that
IIS7 introduces for your own application purposes <strong>without code</strong>.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=7d80160c-6f7f-4865-b0b9-6d181d6a8fdc" />
      </body>
      <title>Discovering IIS7 Schema</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,7d80160c-6f7f-4865-b0b9-6d181d6a8fdc.aspx</guid>
      <link>http://dunnry.com/blog/2007/07/27/DiscoveringIIS7Schema.aspx</link>
      <pubDate>Fri, 27 Jul 2007 21:08:23 GMT</pubDate>
      <description>&lt;p&gt;
One of the major changes introduced with IIS7 is the removal of the metabase.&amp;nbsp;
This probably comes as a great relief to many of the admins and developers that struggled
with coordinating configuration across multiple machines.&amp;nbsp; Instead of the metabase,
IIS7 has chosen to schematize all the web server settings and host them centrally
in a new XML file called applicationHost.config located at '%windir%\system32\inetsrv\config'.
&lt;/p&gt;
&lt;p&gt;
The schema itself can be found in the 'schema' folder right below the 'config' directory.&amp;nbsp;
This new centralized configuration file holds all the global default values for IIS7
as well as defines what sites, applications, virtual directories, app pools, etc.
are on the server.
&lt;/p&gt;
&lt;p&gt;
Let's take a look just a couple items I found in my&amp;nbsp;applicationHost.config:
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;applicationPools&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;add&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;DefaultAppPool&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; /&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;add&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;Classic
.NET AppPool&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;managedPipelineMode&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;Classic&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; /&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;applicationPoolDefaults&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;processModel&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;identityType&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;NetworkService&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; /&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;applicationPoolDefaults&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;applicationPools&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt; 
&lt;p&gt;
Here is the configuration of the application pools on my IIS7 server.&amp;nbsp; Let's
see what happens if we just edit this directly and add a new application pool.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/DiscoveringIIS7Schema_D463/AppPool.png" atomicselection="true"&gt;&lt;img height="196" alt="AppPool" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/DiscoveringIIS7Schema_D463/AppPool_thumb.png" width="525" border="0"&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
If we open our new IIS Manager (Start &amp;gt; Run &amp;gt; inetmgr), we can see that this
is all there is to it.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/DiscoveringIIS7Schema_D463/AppPoolsInManager.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="255" alt="AppPoolsInManager" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/DiscoveringIIS7Schema_D463/AppPoolsInManager_thumb.png" width="640" border="0"&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
Further poking around will yield lists of sites, applications, and virtual directories
as well - all described neatly in XML format.&amp;nbsp; Now, how did the IIS team put
all this together?&amp;nbsp; Were they using their own black box implementation?&amp;nbsp;
If we inspect the schema, we will find there is no magic here and the IIS team is
leveraging its own schema system for IIS itself.&amp;nbsp; Opening the "IIS_Schema.xml"
file found in the 'schema' directory shows us the exact settings available for 'applicationPools'.
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt; &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;sectionSchema&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;system.applicationHost/applicationPools&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;collection&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;addElement&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;add&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;defaultElement&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;applicationPoolDefaults&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;attribute&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;name&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;type&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;required&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;true&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;isUniqueKey&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;true&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;validationType&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;applicationPoolName&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; /&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;attribute&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;queueLength&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;type&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;uint&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;defaultValue&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;1000&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;validationType&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;integerRange&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;validationParameter&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;10,65535&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;/&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;attribute&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;autoStart&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;type&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;bool&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;defaultValue&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;true&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; /&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;attribute&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;enable32BitAppOnWin64&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;type&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;bool&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;defaultValue&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;false&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; /&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;attribute&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;managedRuntimeVersion&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;type&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;string&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;defaultValue&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;v2.0&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; /&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;attribute&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;managedPipelineMode&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;type&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;enum&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;defaultValue&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;Integrated&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;enum&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;Integrated&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;value&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;0&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; /&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;enum&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;Classic&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;value&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;1&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; /&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;attribute&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;attribute&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;passAnonymousToken&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;type&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;bool&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;defaultValue&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;true&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; /&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;element&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;processModel&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;attribute&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;identityType&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;type&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;enum&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;defaultValue&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;NetworkService&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;enum&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;LocalSystem&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;value&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;0&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;/&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;enum&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;LocalService&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;value&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;1&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;/&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;enum&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;NetworkService&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;value&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;2&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;/&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;enum&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;SpecificUser&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;value&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;3&lt;/span&gt;"&lt;span style="color: rgb(0,0,255)"&gt;/&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;attribute&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &amp;lt;...SNIP...&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;sectionSchema&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
As we can see here, there are some basic typed attributes that describe our application
pool.&amp;nbsp; They have things like types, default values, and even enumerations with
possible values (managedPipelineMode is one such).&amp;nbsp; There really is no magic
here.&amp;nbsp; Someone could very easily write a program that inspected the schema of
IIS7 fully and presented all possible options just by inspecting this schema.
&lt;/p&gt;
&lt;p&gt;
What should immediately come to mind as a developer is, "&lt;strong&gt;how can I leverage
this system&lt;/strong&gt;"?&amp;nbsp; If there is one word that describes IIS7, it is "&lt;strong&gt;Extensible&lt;/strong&gt;".&amp;nbsp;
In my next post, I will show you how to leverage this powerful schema system that
IIS7 introduces for your own application purposes &lt;strong&gt;without code&lt;/strong&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=7d80160c-6f7f-4865-b0b9-6d181d6a8fdc" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,7d80160c-6f7f-4865-b0b9-6d181d6a8fdc.aspx</comments>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>IIS</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=d10681bd-a808-4e3d-b761-fe42bd25e6d8</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,d10681bd-a808-4e3d-b761-fe42bd25e6d8.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,d10681bd-a808-4e3d-b761-fe42bd25e6d8.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=d10681bd-a808-4e3d-b761-fe42bd25e6d8</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I was checking on the <a href="http://directoryprogramming.net">book's website</a> the
other day and noticed that we broke the 54,000 mark for downloads of our sample code. 
That really surprised me.  I just didn't think that there were that many people
in the world working on these types of scenarios.
</p>
        <p>
 Now, I happen to know that we did not sell that many copies of <a href="http://www.amazon.com/exec/obidos/redirect?link_code=as2&amp;path=ASIN/0321350170&amp;tag=extemporaneou-20&amp;camp=1789&amp;creative=9325">the
book</a>, so this means a lot of people are downloading just the samples.  For
the record, that is perfectly fine and we encourage people to look at the samples. 
Admittedly, some of the samples might be head-scratchers without the book for context,
but hey, its free and so is our time on <a href="http://directoryprogramming.net/forums/default.aspx">the
forums</a>.
</p>
        <p>
Joe and I log a lot of time here and in other forums helping people and we love to
hear your feedback on what works and what doesn't.  Give us a shout when samples
don't make sense, or when a scenario seems to be overly painful.  Some people
have asked how they can repay us for our time (I have had offers for beer, wine, and
lodging so far).  A simple thanks is enough for both of us, however, and a perhaps
a recommendation to others.  If you really feel the need to contribute beyond
nice words - simple, just <a href="http://www.amazon.com/exec/obidos/redirect?link_code=as2&amp;path=ASIN/0321350170&amp;tag=extemporaneou-20&amp;camp=1789&amp;creative=9325">buy
the book</a>!
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=d10681bd-a808-4e3d-b761-fe42bd25e6d8" />
      </body>
      <title>Directory Services Samples Milestone</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,d10681bd-a808-4e3d-b761-fe42bd25e6d8.aspx</guid>
      <link>http://dunnry.com/blog/2007/06/28/DirectoryServicesSamplesMilestone.aspx</link>
      <pubDate>Thu, 28 Jun 2007 22:00:18 GMT</pubDate>
      <description>&lt;p&gt;
I was checking on the &lt;a href="http://directoryprogramming.net"&gt;book's website&lt;/a&gt; the
other day and noticed that we broke the 54,000 mark for downloads of our sample code.&amp;nbsp;
That really surprised me.&amp;nbsp; I just didn't think that there were that many people
in the world working on these types of scenarios.
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;Now, I happen to know that we did not sell that many copies of &lt;a href="http://www.amazon.com/exec/obidos/redirect?link_code=as2&amp;amp;path=ASIN/0321350170&amp;amp;tag=extemporaneou-20&amp;amp;camp=1789&amp;amp;creative=9325"&gt;the
book&lt;/a&gt;, so this means a lot of people are downloading just the samples.&amp;nbsp; For
the record, that is perfectly fine and we encourage people to look at the samples.&amp;nbsp;
Admittedly, some of the samples might be head-scratchers without the book for context,
but hey, its free and so is our time on &lt;a href="http://directoryprogramming.net/forums/default.aspx"&gt;the
forums&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Joe and I log a lot of time here and in other forums helping people and we love to
hear your feedback on what works and what doesn't.&amp;nbsp; Give us a shout when samples
don't make sense, or when a scenario seems to be overly painful.&amp;nbsp; Some people
have asked how they can repay us for our time (I have had offers for beer, wine, and
lodging so far).&amp;nbsp; A simple thanks is enough for both of us, however, and a perhaps
a recommendation to others.&amp;nbsp; If you really feel the need to contribute beyond
nice words - simple, just &lt;a href="http://www.amazon.com/exec/obidos/redirect?link_code=as2&amp;amp;path=ASIN/0321350170&amp;amp;tag=extemporaneou-20&amp;amp;camp=1789&amp;amp;creative=9325"&gt;buy
the book&lt;/a&gt;!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=d10681bd-a808-4e3d-b761-fe42bd25e6d8" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,d10681bd-a808-4e3d-b761-fe42bd25e6d8.aspx</comments>
      <category>.NET</category>
      <category>Active Directory</category>
      <category>ADAM</category>
      <category>ADSI</category>
      <category>Book</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=87d9e628-5d7d-4aec-9b0a-9c90bfae3495</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,87d9e628-5d7d-4aec-9b0a-9c90bfae3495.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,87d9e628-5d7d-4aec-9b0a-9c90bfae3495.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=87d9e628-5d7d-4aec-9b0a-9c90bfae3495</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I almost missed <a href="http://blogs.dirteam.com/blogs/tomek/archive/2007/05/18/s-ds-and-large-data-sets.aspx">this
one from Tomek</a>, but he has a good analysis of what happens when you have many
results to return from the directory and a nice comparison of how the different stacks
(System.DirectoryServices vs. System.DirectoryServices.Protocols) handle it. 
The moral of the story:  if you have a ton of results coming back, it might be
in your interest to pursue using the Protocols stack.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=87d9e628-5d7d-4aec-9b0a-9c90bfae3495" />
      </body>
      <title>Working with Large Amounts of Data in Directory Services</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,87d9e628-5d7d-4aec-9b0a-9c90bfae3495.aspx</guid>
      <link>http://dunnry.com/blog/2007/06/01/WorkingWithLargeAmountsOfDataInDirectoryServices.aspx</link>
      <pubDate>Fri, 01 Jun 2007 17:39:58 GMT</pubDate>
      <description>&lt;p&gt;
I almost missed &lt;a href="http://blogs.dirteam.com/blogs/tomek/archive/2007/05/18/s-ds-and-large-data-sets.aspx"&gt;this
one from Tomek&lt;/a&gt;, but he has a good analysis of what happens when you have many
results to return from the directory and a nice comparison of how the different stacks
(System.DirectoryServices vs. System.DirectoryServices.Protocols) handle it.&amp;nbsp;
The moral of the story:&amp;nbsp; if you have a ton of results coming back, it might be
in your interest to pursue using the Protocols stack.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=87d9e628-5d7d-4aec-9b0a-9c90bfae3495" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,87d9e628-5d7d-4aec-9b0a-9c90bfae3495.aspx</comments>
      <category>.NET</category>
      <category>Active Directory</category>
      <category>ADAM</category>
      <category>ADSI</category>
      <category>Protocols</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=ecc46aad-45d9-48c2-8280-29f08eb78c8f</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,ecc46aad-45d9-48c2-8280-29f08eb78c8f.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,ecc46aad-45d9-48c2-8280-29f08eb78c8f.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=ecc46aad-45d9-48c2-8280-29f08eb78c8f</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Fellow MVP, Ethan Wilansky has a new article on MSDN outlining the System.DirectoryServices.Protocols
stack.  I haven't had a chance to read every last word in it yet (it's a huge
article!), but it appears to show roughly 80% of everything you might want to do with
SDS.P.  Check it out.
</p>
        <p>
          <a href="http://msdn2.microsoft.com/en-us/library/bb332056.aspx">Link to Introduction
to System.DirectoryServices.Protocols (S.DS.P)</a>
        </p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=ecc46aad-45d9-48c2-8280-29f08eb78c8f" />
      </body>
      <title>Introduction to System.DirectoryServices.Protocols (S.DS.P)</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,ecc46aad-45d9-48c2-8280-29f08eb78c8f.aspx</guid>
      <link>http://dunnry.com/blog/2007/04/15/IntroductionToSystemDirectoryServicesProtocolsSDSP.aspx</link>
      <pubDate>Sun, 15 Apr 2007 22:41:26 GMT</pubDate>
      <description>&lt;p&gt;
Fellow MVP, Ethan Wilansky&amp;nbsp;has a new article on MSDN outlining the System.DirectoryServices.Protocols
stack.&amp;nbsp; I haven't had a chance to read every last word in it yet (it's a huge
article!), but it appears to show roughly 80% of everything you might want to do with
SDS.P.&amp;nbsp; Check it out.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://msdn2.microsoft.com/en-us/library/bb332056.aspx"&gt;Link to Introduction
to System.DirectoryServices.Protocols (S.DS.P)&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=ecc46aad-45d9-48c2-8280-29f08eb78c8f" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,ecc46aad-45d9-48c2-8280-29f08eb78c8f.aspx</comments>
      <category>.NET</category>
      <category>Active Directory</category>
      <category>ADAM</category>
      <category>LDAP</category>
      <category>MVP</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=c89535a9-83a2-4b95-ace3-81f8369db151</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,c89535a9-83a2-4b95-ace3-81f8369db151.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,c89535a9-83a2-4b95-ace3-81f8369db151.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c89535a9-83a2-4b95-ace3-81f8369db151</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
If hot-LDAP-filter-action is your thing, but you were let down in <a href="http://dunnry.com/blog/TransitiveLinkValueFilterEvaluation.aspx">my
last post</a> since it required SP2 and Longhorn, then this should get you all hot
and bothered again:  <a href="http://support.microsoft.com/?kbid=914828">Hotfix
for SP1</a>.
</p>
        <p>
I know, it's a hotfix - which means you have to contact Microsoft to get it. 
But if you want to take advantage of the new LDAP_MATCHING_RULE_IN_CHAIN without upgrading
to SP2 or Longhorn, then this is it.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=c89535a9-83a2-4b95-ace3-81f8369db151" />
      </body>
      <title>Transitive Link Value Filter for SP1</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,c89535a9-83a2-4b95-ace3-81f8369db151.aspx</guid>
      <link>http://dunnry.com/blog/2007/04/05/TransitiveLinkValueFilterForSP1.aspx</link>
      <pubDate>Thu, 05 Apr 2007 17:18:23 GMT</pubDate>
      <description>&lt;p&gt;
If hot-LDAP-filter-action is your thing, but you were let down in &lt;a href="http://dunnry.com/blog/TransitiveLinkValueFilterEvaluation.aspx"&gt;my
last post&lt;/a&gt; since it required SP2 and Longhorn, then this should get you all hot
and bothered again:&amp;nbsp; &lt;a href="http://support.microsoft.com/?kbid=914828"&gt;Hotfix
for SP1&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
I know, it's a hotfix - which means you have to contact Microsoft to get it.&amp;nbsp;
But if you want to take advantage of the new LDAP_MATCHING_RULE_IN_CHAIN without upgrading
to SP2 or Longhorn, then&amp;nbsp;this is it.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=c89535a9-83a2-4b95-ace3-81f8369db151" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,c89535a9-83a2-4b95-ace3-81f8369db151.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>Groups</category>
      <category>LDAP</category>
      <category>tokenGroups</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=247b3d52-71e2-4f88-bf2e-2055c48f83d0</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,247b3d52-71e2-4f88-bf2e-2055c48f83d0.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,247b3d52-71e2-4f88-bf2e-2055c48f83d0.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=247b3d52-71e2-4f88-bf2e-2055c48f83d0</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Straight from <a href="http://blogs.msdn.com/somasegar/archive/2007/04/03/listening-to-your-feedback-expression-and-msdn.aspx">Somasegar</a>. 
This is good news for developers trying to fit in with their visual counterparts. 
Initially these were targeted at the professional designer instead of the developer. 
I personally think that those two overlap quite a bit.  It was a good move to
put this into developer's hands.  You can be sure that they will get used now...
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=247b3d52-71e2-4f88-bf2e-2055c48f83d0" />
      </body>
      <title>Expression Web and Blend on MSDN soon</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,247b3d52-71e2-4f88-bf2e-2055c48f83d0.aspx</guid>
      <link>http://dunnry.com/blog/2007/04/03/ExpressionWebAndBlendOnMSDNSoon.aspx</link>
      <pubDate>Tue, 03 Apr 2007 16:39:30 GMT</pubDate>
      <description>&lt;p&gt;
Straight from &lt;a href="http://blogs.msdn.com/somasegar/archive/2007/04/03/listening-to-your-feedback-expression-and-msdn.aspx"&gt;Somasegar&lt;/a&gt;.&amp;nbsp;
This is good news for developers trying to fit in with their visual counterparts.&amp;nbsp;
Initially these were targeted at the professional designer instead of the developer.&amp;nbsp;
I personally think that those two overlap quite a bit.&amp;nbsp; It was a good move to
put this into developer's hands.&amp;nbsp; You can be sure that they will get used now...
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=247b3d52-71e2-4f88-bf2e-2055c48f83d0" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,247b3d52-71e2-4f88-bf2e-2055c48f83d0.aspx</comments>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Design</category>
      <category>VS.NET</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=37427cd8-659b-43b4-800a-3cd0f0af11d2</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,37427cd8-659b-43b4-800a-3cd0f0af11d2.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,37427cd8-659b-43b4-800a-3cd0f0af11d2.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=37427cd8-659b-43b4-800a-3cd0f0af11d2</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Here is something that I am sure developers will run into as they start to create
web sites on their local Vista boxes using IIS7.  I thought I would just put
this out here to save people some time.  If you are like me, you will go to the
'Turn Windows features on or off' selection and simply check the IIS7 option like
so:
</p>
        <p>
          <a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/features%5B7%5D.png" atomicselection="true">
            <img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="211" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/features_thumb%5B5%5D.png" width="240" border="0" />
          </a>
        </p>
        <p>
If done correctly, this installs the ASP.NET environment and all the appropriate stuff. 
If not, you get an interesting error when you browse to the first .aspx page on your
site.  Specifically, you will get a nice 404.3 error similar to this:
</p>
        <p>
          <a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/iis7-error%5B10%5D.png" atomicselection="true">
            <img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="330" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/iis7-error_thumb%5B8%5D.png" width="472" border="0" />
          </a>
        </p>
        <p>
The part that should tip you off that something is completely misconfigured 
is the part of the the error message (which are sooo much nicer these days) where
the module is being reported as the "<strong>StaticFileModule</strong>".  Static
files are things like .html files, jpegs, etc. where we are not performing any server
side logic.  We know that our .aspx files need to be processed by the .NET runtime,
so we should see something else as the handler there.
</p>
        <p>
Now, here comes the confusing part.  Bring up the IIS Manager (Windows Key &gt;
"Inetmgr"), and view the Handler Mappings for your site and you will see something
similar to this:
</p>
        <p>
          <a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/current-mappings%5B4%5D.png" atomicselection="true">
            <img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="470" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/current-mappings_thumb%5B2%5D.png" width="502" border="0" />
          </a>
        </p>
        <p>
Notice that all of the ASP.NET extensions are missing?  There are no handlers
defined for the .aspx, .asmx, .ashx or any other .NET extensions.  If you bring
up the handlers installed on the machine however, you will see that they are all just
fine:
</p>
        <p>
          <a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/machine-mappings%5B3%5D.png" atomicselection="true">
            <img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="465" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/machine-mappings_thumb%5B1%5D.png" width="500" border="0" />
          </a>
        </p>
        <p>
At this point, you may be like me and scratching your head asking, "<strong>why are
my handlers not being inherited correctly</strong>"?  If you are like me, then
you will probably try delete your web app and then re-add it back. 
When that fails you will try to uninstall and reinstall IIS7 again. 
When that doesn't work, you will try to reinstall ASP.NET manually from the command
line using "aspnet_regiis -i" or something similar.  When that fails, you will
spend hours on Google trying to see <a href="http://forums.iis.net/thread/1406429.aspx">what
other people have done</a>.  It might also cross your mind to just add them manually
to your configuration.  If you are like me, however, that seems dirty and you
will keep trying.
</p>
        <p>
To save you some time, it actually turns out it is pretty easy to fix.  Simply <strong>DELETE</strong> the
"Default Web Site", and then <strong>ADD</strong> it back.  The Handlers will
be re-applied correctly and your virtual directory or web site will have all the correct
handlers installed.  It is confusing why this even happens with a fresh install,
but it appears to be a frequent occurrence according to Google searches.  Coming
from IIS 5.1 and 6, it might be counterintuitive to delete a site, but this is actually
not a big deal in Vista since you can have as many of these as you like (no artificial
limits anymore).  I hope this saves someone some time.
</p>
        <p>
          <strong>Note to the IIS7 team</strong>:  <em>man, it would really be nice if
you had a button that said something like "apply inherited handlers" or something
like that</em>.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=37427cd8-659b-43b4-800a-3cd0f0af11d2" />
      </body>
      <title>IIS7 and 404.3 Error</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,37427cd8-659b-43b4-800a-3cd0f0af11d2.aspx</guid>
      <link>http://dunnry.com/blog/2007/03/30/IIS7And4043Error.aspx</link>
      <pubDate>Fri, 30 Mar 2007 17:25:18 GMT</pubDate>
      <description>&lt;p&gt;
Here is something that I am sure developers will run into as they start to create
web sites on their local Vista boxes using IIS7.&amp;nbsp; I thought I would just put
this out here to save people some time.&amp;nbsp; If you are like me, you will go to the
'Turn Windows features on or off' selection and simply check the IIS7 option like
so:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/features%5B7%5D.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="211" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/features_thumb%5B5%5D.png" width="240" border="0"&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
If done correctly, this installs the ASP.NET environment and all the appropriate stuff.&amp;nbsp;
If not, you get an interesting error when you browse to the first .aspx page on your
site.&amp;nbsp; Specifically, you will get a nice 404.3 error similar to this:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/iis7-error%5B10%5D.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="330" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/iis7-error_thumb%5B8%5D.png" width="472" border="0"&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
The part that should tip you off that something is completely misconfigured&amp;nbsp;
is the part of the the error message (which are sooo much nicer these days) where
the module is being reported as the "&lt;strong&gt;StaticFileModule&lt;/strong&gt;".&amp;nbsp; Static
files are things like .html files, jpegs, etc. where we are not performing any server
side logic.&amp;nbsp; We know that our .aspx files need to be processed by the .NET runtime,
so we should see something else as the handler there.
&lt;/p&gt;
&lt;p&gt;
Now, here comes the confusing part.&amp;nbsp; Bring up the IIS Manager (Windows Key &amp;gt;
"Inetmgr"), and view the Handler Mappings for your site&amp;nbsp;and you will see something
similar to this:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/current-mappings%5B4%5D.png" atomicselection="true"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="470" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/current-mappings_thumb%5B2%5D.png" width="502" border="0"&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
Notice that all of the ASP.NET extensions are missing?&amp;nbsp; There are no handlers
defined for the .aspx, .asmx, .ashx or any other .NET extensions.&amp;nbsp; If you bring
up the handlers installed on the machine however, you will see that they are all just
fine:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/machine-mappings%5B3%5D.png" atomicselection="true"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="465" src="http://dunnry.com/blog/content/binary/WindowsLiveWriter/IIS7and404.3Error_9268/machine-mappings_thumb%5B1%5D.png" width="500" border="0"&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
At this point, you may be like me and scratching your head asking, "&lt;strong&gt;why are
my handlers not being inherited correctly&lt;/strong&gt;"?&amp;nbsp; If you are like me, then
you will probably try&amp;nbsp;delete your&amp;nbsp;web app and then re-add it back.&amp;nbsp;
When that fails you&amp;nbsp;will try&amp;nbsp;to uninstall and reinstall IIS7 again.&amp;nbsp;
When that doesn't work, you will try to reinstall ASP.NET manually from the command
line using "aspnet_regiis -i" or something similar.&amp;nbsp; When that fails, you will
spend hours on Google trying to see &lt;a href="http://forums.iis.net/thread/1406429.aspx"&gt;what
other people have done&lt;/a&gt;.&amp;nbsp; It might also cross your mind to just add them manually
to your configuration.&amp;nbsp; If you are like me, however, that seems dirty and you
will keep trying.
&lt;/p&gt;
&lt;p&gt;
To save you some time, it actually turns out it is pretty easy to fix.&amp;nbsp; Simply &lt;strong&gt;DELETE&lt;/strong&gt; the
"Default Web Site", and then &lt;strong&gt;ADD&lt;/strong&gt; it back.&amp;nbsp; The Handlers will
be re-applied correctly and your virtual directory or web site will have all the correct
handlers installed.&amp;nbsp; It is confusing why this even happens with a fresh install,
but it appears to be a frequent occurrence according to Google searches.&amp;nbsp; Coming
from IIS 5.1 and 6, it might be counterintuitive to delete a site, but this is actually
not a big deal in Vista since you can have as many of these as you like (no artificial
limits anymore).&amp;nbsp; I hope this saves someone some time.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Note to the IIS7 team&lt;/strong&gt;:&amp;nbsp; &lt;em&gt;man, it would really be nice if
you had a button that said something like "apply inherited handlers" or something
like that&lt;/em&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=37427cd8-659b-43b4-800a-3cd0f0af11d2" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,37427cd8-659b-43b4-800a-3cd0f0af11d2.aspx</comments>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>DasBlog</category>
      <category>Tips</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=b0a29f56-68c1-4bff-bf85-ed233ead3e86</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,b0a29f56-68c1-4bff-bf85-ed233ead3e86.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,b0a29f56-68c1-4bff-bf85-ed233ead3e86.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=b0a29f56-68c1-4bff-bf85-ed233ead3e86</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I was speaking with <a href="http://blogs.technet.com/efleis/">Eric Fleischman</a> at
the MVP summit this year and he told me about a neat feature you will find in Window
Server 2003 SP2 and Longhorn server.  It is a new type of matching rule ID filter
that allows for transitive link value evaluation.  This is one filter type that
is incredibly useful and you will want to know about.
</p>
        <p>
First some background: a matching rule ID filter is a special syntax filter that allows
for an arbitrary search behavior as defined by the matching rule.  Active Directory
and ADAM only shipped with two matching rules until recently: LDAP_MATCHING_RULE_BIT_AND
(1.2.840.113556.1.4.803) and LDAP_MATCHING_RULE_BIT_OR (1.2.840.113556.1.4.804). 
We commonly used these matching rules to check our bitwise flag values.  For
instance, here is the key portion of the filter that specifies an account is disabled:
</p>
        <p>
          <code>(userAccountControl:1.2.840.113556.1.4.803:=2)</code>
        </p>
        <p>
Notice that we have the attribute name we are searching on, the rule OID we want to
use (the AND rule), and the value to check (in decimal).  Pretty simple, right?
</p>
        <p>
The new matching rule is called LDAP_MATCHING_RULE_IN_CHAIN and it has an OID of 1.2.840.113556.1.4.1941. 
This new rule allows us to search across all DN-syntax attributes recursively and
evaluate the entire tree of relationships (hence the transitive name).
</p>
        <p>
          <strong>Evaluating Group Membership</strong>
        </p>
        <p>
Where we will typically see this used is in group membership evaluation.  Specifically,
it answers two questions that are constantly asked by developers:  What groups
are my user a member of? and What users are in this group?
</p>
        <p>
It is really simple to use this filter, so here we go.  The first question is,
what groups is my user a member of?
</p>
        <p>
          <code>(member:1.2.840.113556.1.4.1941:=CN=User1,OU=X,DC=domain,DC=com)</code>
        </p>
        <p>
The next question, what users are in this group?
</p>
        <p>
          <code>(memberOf:1.2.840.113556.1.4.1941:=CN=A Group,OU=Y,DC=domain,DC=com)</code>
        </p>
        <p>
If we place base this search on the main partition and use a subtree search, it will
return for us all the matches across the domain.  However, if we scope the second
search to a specific user object and use a base search, it is a quick and dirty way
of telling us if the user is a member of the group.  Hence, this would also work
for a type of IsInRole() function:
</p>
        <p>
          <code>public bool IsUserMember(DirectoryEntry user, string groupDN) 
<br />
{<br />
    string filter = String.Format(<br />
        "(memberOf:1.2.840.113556.1.4.1941:={0})",
groupDN);<br /><br />
    DirectorySearcher ds = new DirectorySearcher(<br />
        user,<br />
        filter,<br />
        null,<br />
        SearchScope.Base);<br /><br />
    return (ds.FindOne() != null);<br />
}</code>
        </p>
        <p>
Now, I want to also point out that this sort of code also makes me cringe a little
bit thinking about the abuse that can occur...  Remember, it is performing a
search each and every time you want to check group membership.  It is still a
better idea to build the entire group membership of a user and store it in one of
the IPrincipal classes and use the .IsInRole() functionality to keep network access
to a minimum.
</p>
        <p>
          <strong>Creating an Org Chart</strong>
        </p>
        <p>
The other area where we will find this filter being pretty handy is when we want to
find all the users that directly and indirectly report to a single person.  This
is the typical situation when building org charts or trying to find the users for
a mailing list.  Here is one such example:
</p>
        <p>
          <code>public static void GetOrgChart(DirectoryEntry entry, string bossDN)<br />
{<br />
    string filter = String.Format(<br />
        "(&amp;(mail=*)(manager:1.2.840.113556.1.4.1941:={0}))",<br />
        bossDN);<br /><br />
    DirectorySearcher ds = new DirectorySearcher(<br />
        entry,<br />
        filter<br />
        );<br /><br />
    using (SearchResultCollection src = ds.FindAll())<br />
    {<br />
        foreach (SearchResult sr in src)<br />
        {<br />
            Console.WriteLine(sr.Properties["mail"][0]);<br />
        }<br />
    } 
<br />
}</code>   
</p>
        <p>
          <strong>Performance</strong>
        </p>
        <p>
The next question we will want to answer for this new filter type is the performance
relative to the code required to process this recursively.  I will use the code <a href="http://dunnry.com/blog/ARecursivePatternForDNSyntaxAttributesPart2.aspx">I
presented here</a> to test the recursive case and compare it to a simple filter of:
</p>
        <p>
          <code>(memberOf:1.2.840.113556.1.4.1941:=CN=BigNestedGroup,OU=X,DC=Y)</code>
        </p>
        <p>
So, to cut to the chase, how does the new filter compare to recursively chasing DN link
pairs yourself?  Short answer... it doesn't.  The code I wrote for the book
and here on the blog blows it away by a factor of 10.  I have to admit that before
I ran the tests, I expected the new filter to run circles around my code and I was
pretty shocked when the reverse was actually true.  I tested this using 3 nested
groups each with 100 members and running both the recursive search and the transitive
search 100 times and averaging the results.  To expand the lead group with 300
direct and indirect members took roughly half a second using a transitive filter (409ms)
as compared to only (41ms) using the recursive search.  This would have
a big impact on server apps serving many of these searches, but would probably not
be a huge factor in client side apps or where a smallish number of these searches
are performed.
</p>
        <p>
          <strong>Summary</strong>
        </p>
        <p>
The transitive filter is a great new addition and can greatly simplify the code that
you have to write.  This new filter is not without pitfalls however.  Make
sure you are cognizant of the performance tradeoffs that are inherent in choosing
this filter as it is considerably slower to use. 
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=b0a29f56-68c1-4bff-bf85-ed233ead3e86" />
      </body>
      <title>Transitive Link Value Filter Evaluation</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,b0a29f56-68c1-4bff-bf85-ed233ead3e86.aspx</guid>
      <link>http://dunnry.com/blog/2007/03/20/TransitiveLinkValueFilterEvaluation.aspx</link>
      <pubDate>Tue, 20 Mar 2007 20:16:36 GMT</pubDate>
      <description>&lt;p&gt;
I was speaking with &lt;a href="http://blogs.technet.com/efleis/"&gt;Eric Fleischman&lt;/a&gt; at
the MVP summit this year and he told me about a neat feature you will find in Window
Server 2003 SP2 and Longhorn server.&amp;nbsp; It is a new type of matching rule ID filter
that allows for transitive link value evaluation.&amp;nbsp; This is one filter type that
is incredibly useful and you will want to know about.
&lt;/p&gt;
&lt;p&gt;
First some background: a matching rule ID filter is a special syntax filter that allows
for an arbitrary search behavior as defined by the matching rule.&amp;nbsp; Active Directory
and ADAM only shipped with two matching rules until recently: LDAP_MATCHING_RULE_BIT_AND
(1.2.840.113556.1.4.803)&amp;nbsp;and LDAP_MATCHING_RULE_BIT_OR (1.2.840.113556.1.4.804).&amp;nbsp;
We commonly used these matching rules to check our bitwise flag values.&amp;nbsp; For
instance, here is the key portion of the filter that specifies an account is disabled:
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;(userAccountControl:1.2.840.113556.1.4.803:=2)&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
Notice that we have the attribute name we are searching on, the rule OID we want to
use (the AND rule), and the value to check (in decimal).&amp;nbsp; Pretty simple, right?
&lt;/p&gt;
&lt;p&gt;
The new matching rule is called LDAP_MATCHING_RULE_IN_CHAIN and it has an OID of 1.2.840.113556.1.4.1941.&amp;nbsp;
This new rule allows us to search across all DN-syntax attributes recursively and
evaluate the entire tree of relationships (hence the transitive name).
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Evaluating Group Membership&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
Where we will typically see this used is in group membership evaluation.&amp;nbsp; Specifically,
it answers two questions that are constantly asked by developers:&amp;nbsp; What groups
are my user a member of? and What users are in this group?
&lt;/p&gt;
&lt;p&gt;
It is really simple to use this filter, so here we go.&amp;nbsp; The first question is,
what groups is my user a member of?
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;(member:1.2.840.113556.1.4.1941:=CN=User1,OU=X,DC=domain,DC=com)&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
The next question, what users are in this group?
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;(memberOf:1.2.840.113556.1.4.1941:=CN=A Group,OU=Y,DC=domain,DC=com)&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
If we place base this search on the main partition and use a subtree search, it will
return for us all the matches across the domain.&amp;nbsp; However, if we scope the second
search to a specific user object and use a base search, it is a quick and dirty way
of telling us if the user is a member of the group.&amp;nbsp; Hence, this would also work
for a type of IsInRole() function:
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;public bool IsUserMember(DirectoryEntry user, string groupDN) 
&lt;br&gt;
{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string filter = String.Format(&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "(memberOf:1.2.840.113556.1.4.1941:={0})",
groupDN);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DirectorySearcher ds = new DirectorySearcher(&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; user,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;filter,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;null,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;SearchScope.Base);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return (ds.FindOne() != null);&lt;br&gt;
}&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
Now, I want to also point out that this sort of code also makes me cringe a little
bit thinking about the abuse that can occur...&amp;nbsp; Remember, it is performing a
search each and every time you want to check group membership.&amp;nbsp; It is still a
better idea to build the entire group membership of a user and store it in one of
the IPrincipal classes and use the .IsInRole() functionality to keep network access
to a minimum.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Creating an Org Chart&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
The other area where we will find this filter being pretty handy is when we want to
find all the users that directly and indirectly report to a single person.&amp;nbsp; This
is the typical situation when building org charts or trying to find the users for
a mailing list.&amp;nbsp;&amp;nbsp;Here is one such example:
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;public static void GetOrgChart(DirectoryEntry entry, string bossDN)&lt;br&gt;
{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; string filter = String.Format(&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "(&amp;amp;(mail=*)(manager:1.2.840.113556.1.4.1941:={0}))",&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;bossDN);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; DirectorySearcher ds = new DirectorySearcher(&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; entry,&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; filter&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; );&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; using (SearchResultCollection src = ds.FindAll())&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (SearchResult sr in src)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine(sr.Properties["mail"][0]);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} 
&lt;br&gt;
}&lt;/code&gt;&amp;nbsp;&amp;nbsp; 
&lt;p&gt;
&lt;strong&gt;Performance&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
The next question we will want to answer for this new filter type is the performance
relative to the code required to process this recursively.&amp;nbsp; I will use the code &lt;a href="http://dunnry.com/blog/ARecursivePatternForDNSyntaxAttributesPart2.aspx"&gt;I
presented here&lt;/a&gt; to test the recursive case and compare it to a simple filter of:
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;(memberOf:1.2.840.113556.1.4.1941:=CN=BigNestedGroup,OU=X,DC=Y)&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
So, to cut to the chase, how does the new filter compare to recursively chasing DN&amp;nbsp;link
pairs yourself?&amp;nbsp; Short answer... it doesn't.&amp;nbsp; The code I wrote for the book
and here on the blog blows it away by a factor of 10. &amp;nbsp;I have to admit that before
I ran the tests, I expected the new filter to run circles around my code and I was
pretty shocked when the reverse was actually true.&amp;nbsp; I tested this using 3 nested
groups each with 100 members and running both the recursive search and the transitive
search 100 times and averaging the results.&amp;nbsp; To expand the lead group with 300
direct and indirect members took roughly half a second using a transitive filter (409ms)
as compared to&amp;nbsp;only (41ms) using the recursive search.&amp;nbsp; This would have
a big impact on server apps serving many of these searches, but would probably not
be a huge factor in client side apps or where a smallish number of these searches
are performed.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Summary&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
The transitive filter is a great new addition and can greatly simplify the code that
you have to write.&amp;nbsp; This new filter is not without pitfalls however.&amp;nbsp; Make
sure you are cognizant of the performance tradeoffs that are inherent in choosing
this filter as it is considerably slower to use.&amp;nbsp;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=b0a29f56-68c1-4bff-bf85-ed233ead3e86" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,b0a29f56-68c1-4bff-bf85-ed233ead3e86.aspx</comments>
      <category>.NET</category>
      <category>Active Directory</category>
      <category>ADAM</category>
      <category>ADSI</category>
      <category>Groups</category>
      <category>LDAP</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=2417b275-389f-4bbc-9644-faf303d5c937</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,2417b275-389f-4bbc-9644-faf303d5c937.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,2417b275-389f-4bbc-9644-faf303d5c937.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=2417b275-389f-4bbc-9644-faf303d5c937</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I have been playing with a new look for the site. I think this particular one is a
bit cleaner looking than the previous one that shipped with DasBlog. I know that there
are some bugs to be worked out, but I like it well enough that I think I will go ahead
and put the site live with the new look and tweak stuff later (it is mostly the admin
UI).
</p>
        <p>
What do you think?
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=2417b275-389f-4bbc-9644-faf303d5c937" />
      </body>
      <title>A New Look</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,2417b275-389f-4bbc-9644-faf303d5c937.aspx</guid>
      <link>http://dunnry.com/blog/2007/03/12/ANewLook.aspx</link>
      <pubDate>Mon, 12 Mar 2007 07:36:06 GMT</pubDate>
      <description>&lt;p&gt;
I have been playing with a new look for the site. I think this particular one is a
bit cleaner looking than the previous one that shipped with DasBlog. I know that there
are some bugs to be worked out, but I like it well enough that I think I will go ahead
and put the site live with the new look and tweak stuff later (it is mostly the admin
UI).
&lt;/p&gt;
&lt;p&gt;
What do you think?
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=2417b275-389f-4bbc-9644-faf303d5c937" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,2417b275-389f-4bbc-9644-faf303d5c937.aspx</comments>
      <category>.NET</category>
      <category>DasBlog</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=d7e0e573-c3c1-4e98-85cf-a21c429ea29b</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,d7e0e573-c3c1-4e98-85cf-a21c429ea29b.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,d7e0e573-c3c1-4e98-85cf-a21c429ea29b.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=d7e0e573-c3c1-4e98-85cf-a21c429ea29b</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
One of the neater abstractions we get using ASP.NET 2.0 is the ObjectDataSource. Essentially
it allows us to specify our own objects or some arbitrary object graph as a datasource
for databinding operations. Combined with the new GridView class it can be very powerful.
Built in to both of these objects are methods for Selecting, Updating, Deleting, and
Inserting. This allows you to plug-in your own code to manage each of these operations.
</p>
        <p>
If we want to adapt this to support reading and updating (including adds and deletes)
from AD or ADAM, we just need to put a few methods in place and hook them into the
ObjectDataSource abstraction. The nice thing here is that it includes parameter support
pretty easily. This allows us to add new values or update existing values. By specifying
a data key (DataKeyNames) on the Gridview, it also allows us to uniquely index which
object we are modifying.
</p>
        <p>
I chose for this example to show a simple Select, Update, and Delete using a GridView
and the ObjectDataSource. It only required me to configure 3 methods (one for each)
and declaratively setup the parameters I would be using. I chose to use the 'objectGuid'
for the key name since this is guaranteed to be unique and will always point me to
the right object. However, I could also have used the DN as the key value in this
case as well. If I had done that, it would have saved me a little bit of complication
due to the need to rebind when using the GUID value for certain operations.
</p>
        <p>
Keep in mind that this is just a simple sample of how this can be done and is not
something that should be put into production as-is. The whole point of this is to
show how the GridView gives us easy updating and reading of values, while the ObjectDataSource
is used as our abstraction for operations on data. In the past, this would not have
worked well because the DataGrid was so geared towards relational data like SQL. It
would have been much more convoluted to get the same functionality. Being able to
write only 3 methods and have working ASP.NET viewing and editing application is pretty
neat.
</p>
        <p>
You can <a href="http://dunnry.com/blog/content/binary/LdapObjectDataSource.zip">download
the sample here</a>.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=d7e0e573-c3c1-4e98-85cf-a21c429ea29b" />
      </body>
      <title>ASP.NET ObjectDataSource and LDAP</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,d7e0e573-c3c1-4e98-85cf-a21c429ea29b.aspx</guid>
      <link>http://dunnry.com/blog/2007/02/09/ASPNETObjectDataSourceAndLDAP.aspx</link>
      <pubDate>Fri, 09 Feb 2007 17:51:24 GMT</pubDate>
      <description>&lt;p&gt;
One of the neater abstractions we get using ASP.NET 2.0 is the ObjectDataSource. Essentially
it allows us to specify our own objects or some arbitrary object graph as a datasource
for databinding operations. Combined with the new GridView class it can be very powerful.
Built in to both of these objects are methods for Selecting, Updating, Deleting, and
Inserting. This allows you to plug-in your own code to manage each of these operations.
&lt;/p&gt;
&lt;p&gt;
If we want to adapt this to support reading and updating (including adds and deletes)
from AD or ADAM, we just need to put a few methods in place and hook them into the
ObjectDataSource abstraction. The nice thing here is that it includes parameter support
pretty easily. This allows us to add new values or update existing values. By specifying
a data key (DataKeyNames) on the Gridview, it also allows us to uniquely index which
object we are modifying.
&lt;/p&gt;
&lt;p&gt;
I chose for this example to show a simple Select, Update, and Delete using a GridView
and the ObjectDataSource. It only required me to configure 3 methods (one for each)
and declaratively setup the parameters I would be using. I chose to use the 'objectGuid'
for the key name since this is guaranteed to be unique and will always point me to
the right object. However, I could also have used the DN as the key value in this
case as well. If I had done that, it would have saved me a little bit of complication
due to the need to rebind when using the GUID value for certain operations.
&lt;/p&gt;
&lt;p&gt;
Keep in mind that this is just a simple sample of how this can be done and is not
something that should be put into production as-is. The whole point of this is to
show how the GridView gives us easy updating and reading of values, while the ObjectDataSource
is used as our abstraction for operations on data. In the past, this would not have
worked well because the DataGrid was so geared towards relational data like SQL. It
would have been much more convoluted to get the same functionality. Being able to
write only 3 methods and have working ASP.NET viewing and editing application is pretty
neat.
&lt;/p&gt;
&lt;p&gt;
You can &lt;a href="http://dunnry.com/blog/content/binary/LdapObjectDataSource.zip"&gt;download
the sample here&lt;/a&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=d7e0e573-c3c1-4e98-85cf-a21c429ea29b" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,d7e0e573-c3c1-4e98-85cf-a21c429ea29b.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
      <category>ASP.NET</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=5bb9ff81-4e17-4f8d-ae90-d6acc545f193</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,5bb9ff81-4e17-4f8d-ae90-d6acc545f193.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,5bb9ff81-4e17-4f8d-ae90-d6acc545f193.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=5bb9ff81-4e17-4f8d-ae90-d6acc545f193</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
The task of figuring out your Active Directory NETBIOS domain name comes up now and
again.  This is the process of turning something like "DC=yourdomain,DC=com"
into something like "YOURDOMAIN".  This is important if you want to do things
like prefix this name on the 'sAMAccountName' of a user for instance.  There
are three ways of doing this (perhaps more).  I will cover each broadly.
</p>
        <h3>Guess
</h3>
        <p>
Yes, that's right.  You can pretty much guess what it is by parsing the DN of
the defaultNamingContext.  If you had something like "DC=yourdomain,DC=com",
it seems a pretty good guess that the NETBIOS name is "YOURDOMAIN".  However,
this method of course is not foolproof.  For whatever reason, your Active Directory
admins might have decided to do something stupid - like say add a big dash (-) and
some other random nonsense into the NETBIOS name.  Who knows why they do this,
but hey, they can and do (I suspect they hate their users).  So, in this case,
"DC=yourdomain,DC=com" might have a NETBIOS name of "YOURDOMAIN-CORP" for instance
(it also means you have to type this every damn time you need to supply credentials
as well in NT4 domain\user format).
</p>
        <h3>DsCrackNames
</h3>
        <p>
You can simply use DsCrackNames to convert from DN format to NT4 format and it will
work fine.  Pass the DN (e.g. "DC=yourdomain,DC=com") and you will get back the
NETBIOS name.  This includes IADsNameTranslate if that is up your alley too. 
Since there is no easy way to use either from .NET unless you <a href="http://dunnry.com/blog/DsCrackNamesInNET.aspx">build
your own</a>, this might not be your first choice.
</p>
        <h3>LDAP Query
</h3>
        <p>
Finally, we get to the last method.  First, we connect to the RootDSE of the
domain and inspect the following two properties:  "configurationNamingContext"
and "defaultNamingContext".  Then we bind to the configuration partition (using
the first of these properties) and perform the following search:  (&amp;(objectCategory=crossRef)(nCName={0}))
where {0} is the value you just got from the RootDSE for the 'defaultNamingContext'. 
You should get one result.  Now, just read back the 'nETBIOSName' attribute and
there you have it.
</p>
        <p>
If you are shipping software that needs to do this, obviously you should use one of
the last two methods.  Guessing probably will just not cut it for anything that
is just not quick and dirty.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=5bb9ff81-4e17-4f8d-ae90-d6acc545f193" />
      </body>
      <title>Getting the NETBIOS domain name</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,5bb9ff81-4e17-4f8d-ae90-d6acc545f193.aspx</guid>
      <link>http://dunnry.com/blog/2007/01/25/GettingTheNETBIOSDomainName.aspx</link>
      <pubDate>Thu, 25 Jan 2007 00:26:17 GMT</pubDate>
      <description>&lt;p&gt;
The task of figuring out your Active Directory NETBIOS domain name comes up now and
again.&amp;nbsp; This is the process of turning something like "DC=yourdomain,DC=com"
into something like "YOURDOMAIN".&amp;nbsp; This is important if you want to do things
like prefix this name on the 'sAMAccountName' of a user for instance.&amp;nbsp; There
are three ways of doing this (perhaps more).&amp;nbsp; I will cover each broadly.
&lt;/p&gt;
&lt;h3&gt;Guess
&lt;/h3&gt;
&lt;p&gt;
Yes, that's right.&amp;nbsp; You can pretty much guess what it is by parsing the DN of
the defaultNamingContext.&amp;nbsp; If you had something like "DC=yourdomain,DC=com",
it seems a pretty good guess that the NETBIOS name is "YOURDOMAIN".&amp;nbsp; However,
this method of course is not foolproof.&amp;nbsp; For whatever reason, your Active Directory
admins might have decided to do something stupid - like say add a big dash (-) and
some other random nonsense into the NETBIOS name.&amp;nbsp; Who knows why they do this,
but hey, they can and do (I suspect they hate their users).&amp;nbsp; So, in this case,
"DC=yourdomain,DC=com" might have a NETBIOS name of "YOURDOMAIN-CORP" for instance
(it also means you have to type this every damn time you need to supply credentials
as well in NT4 domain\user format).
&lt;/p&gt;
&lt;h3&gt;DsCrackNames
&lt;/h3&gt;
&lt;p&gt;
You can simply use DsCrackNames to convert from DN format to NT4 format and it will
work fine.&amp;nbsp; Pass the DN (e.g. "DC=yourdomain,DC=com") and you will get back the
NETBIOS name.&amp;nbsp; This includes IADsNameTranslate if that is up your alley too.&amp;nbsp;
Since there is no easy way to use either from .NET unless you &lt;a href="http://dunnry.com/blog/DsCrackNamesInNET.aspx"&gt;build
your own&lt;/a&gt;, this might not be your first choice.
&lt;/p&gt;
&lt;h3&gt;LDAP Query
&lt;/h3&gt;
&lt;p&gt;
Finally, we get to the last method.&amp;nbsp; First, we connect to the RootDSE of the
domain and inspect the following two properties:&amp;nbsp; "configurationNamingContext"
and "defaultNamingContext".&amp;nbsp; Then we bind to the configuration partition (using
the first of these properties) and perform the following search:&amp;nbsp; (&amp;amp;(objectCategory=crossRef)(nCName={0}))
where {0} is the value you just got from the RootDSE for the 'defaultNamingContext'.&amp;nbsp;
You should get one result.&amp;nbsp; Now, just read back the 'nETBIOSName' attribute and
there you have it.
&lt;/p&gt;
&lt;p&gt;
If you are shipping software that needs to do this, obviously you should use one of
the last two methods.&amp;nbsp; Guessing probably will just not cut it for anything that
is just not quick and dirty.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=5bb9ff81-4e17-4f8d-ae90-d6acc545f193" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,5bb9ff81-4e17-4f8d-ae90-d6acc545f193.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=96398858-4504-45f0-bc84-c4ea18c1f9a9</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,96398858-4504-45f0-bc84-c4ea18c1f9a9.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,96398858-4504-45f0-bc84-c4ea18c1f9a9.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=96398858-4504-45f0-bc84-c4ea18c1f9a9</wfw:commentRss>
      <title>Asynchronous LDAP Searching with System.DirectoryServices.Protocols</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,96398858-4504-45f0-bc84-c4ea18c1f9a9.aspx</guid>
      <link>http://dunnry.com/blog/2006/10/31/AsynchronousLDAPSearchingWithSystemDirectoryServicesProtocols.aspx</link>
      <pubDate>Tue, 31 Oct 2006 01:33:42 GMT</pubDate>
      <description>&lt;p&gt;
I have been hanging on to this post for some time now and never getting around to
polishing it up and putting it out.&amp;nbsp; Eric Fleischman&amp;rsquo;s &lt;a href="http://blogs.technet.com/efleis/archive/2006/10/26/finding-the-lost-found-container-in-s-ds-p-or-anything-that-isn-t-adsi-really.aspx"&gt;recent
posting&lt;/a&gt; on SDS.P has inspired me to get some more content out there, however.&amp;nbsp;
For whatever reason, this is a poorly documented topic that probably deserves a series
of postings on it.&amp;nbsp; We neglected this topic mostly in &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0321350170/extemporaneou-20-20"&gt;the
book&lt;/a&gt;&amp;nbsp;because we had concerns about exceeding a certain # of pages on an already
pretty dense topic.&amp;nbsp; I wonder if there would be any demand for a book on this
subject?
&lt;/p&gt;
&lt;p&gt;
Previously, I &lt;a href="http://dunnry.com/blog/PagingInSystemDirectoryServicesProtocols.aspx"&gt;demonstrated&lt;/a&gt; how
you need to perform paging in SDS.P using the cookie and the paging control.&amp;nbsp;
There is a lot more to take care of here than how it is done with ADSI and System.DirectoryServices
(SDS).&amp;nbsp; Now, what if we really wanted to perform this type of search asynchronously?&amp;nbsp;
We actually wrote a sample in the book to show how asynchronous searching is done
in SDS.P, but to keep it simple I left out the whole problem of paging.&amp;nbsp; Let&amp;rsquo;s
be honest, any useful searching is probably going to need to handle paging as well.
&lt;/p&gt;
&lt;p&gt;
SDS.P supports asynchronous searching directly, unlike SDS.&amp;nbsp; It is entirely possible
to emulate this behavior in SDS by leveraging a general asynchronous pattern supported
in .NET (e.g. by way of delegates, background thread workers, or the thread pool),
but there is nothing in SDS to support asynchronously searching directly.&amp;nbsp; Hold
on you say!&amp;nbsp; What about .NET 2.0 and the fancy new property on the DirectorySearcher
called Asynchronous?&amp;nbsp; That is what we call a very misleading property.&amp;nbsp;
While it actually sets the underlying ADS_SEARCHPREF_ASYNCHRONOUS option on the IDirectorySearch
interface, the SDS model consumes the results synchronously, netting you exactly nothing.&amp;nbsp;
I honestly wish they (the SDS .NET team) would just not have exposed that one if you
couldn&amp;rsquo;t really use it.
&lt;/p&gt;
&lt;p&gt;
Let&amp;rsquo;s look at the most basic pattern for how this can be accomplished:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a connection to the LDAP directory (LdapConnection).&lt;/li&gt;
&lt;li&gt;
Create a searching request operation (SearchRequest)&lt;/li&gt;
&lt;li&gt;
Add a paging control to the SearchRequest to control paging&lt;/li&gt;
&lt;li&gt;
Invoke the method asynchronously using LdapConnection.BeginSendRequest&lt;/li&gt;
&lt;li&gt;
Provide a callback method to handle the results.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
Simple, no?&amp;nbsp; It actually looks harder than it is.
&lt;/p&gt;
&lt;p&gt;
When I set out creating this sample, I had a particular use in mind.&amp;nbsp; Specifically,
I wanted to create an easy&amp;nbsp;searching object &amp;ndash; something where I wouldn&amp;rsquo;t
have to worry about paging and that could also handle performing multiple searches
on the same instance.&amp;nbsp; That last point, as you will see makes for additional
complication.&amp;nbsp; I started with my usage model or how I visualized that I wanted
to use it:
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Consolas"&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="COLOR: blue"&gt;using&lt;/span&gt; (LdapConnection
connection = CreateConnection(servername))&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;{&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; AsyncSearcher searcher = CreateSearcher(connection);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//this
call is asynch, so we need to keep this main&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//thread
alive in order to see anything&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//we
can use the same searcher for multiple requests - we just have to track which one&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//is
which, so we can interpret the results later in our events.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; _firstSearch = searcher.BeginPagedSearch(baseDN, &lt;span style="COLOR: maroon"&gt;"(sn=d*)"&lt;/span&gt;, &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;,
500);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; _secondSearch = searcher.BeginPagedSearch(baseDN, &lt;span style="COLOR: maroon"&gt;"(sn=f*)"&lt;/span&gt;, &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;,
500);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//we
will use a reset event to signal when we are done (using Sleep() on&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//current
thread would work too...)&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; _resetEvent.WaitOne(); &lt;span style="COLOR: green"&gt;//wait
for signal;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
I also knew that I would want to be notified of a couple key events that would occur
with my object.&amp;nbsp; Specifically, whenever a page was returned and when the final
search was complete:
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Consolas"&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="COLOR: blue"&gt;static&lt;/span&gt; AsyncSearcher
CreateSearcher(LdapConnection connection)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;{&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; AsyncSearcher searcher = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; AsyncSearcher(connection);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//assign
some handlers for our events&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; searcher.PageCompleted += &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;EventHandler&lt;/span&gt;&amp;lt;AsyncEventArgs&amp;gt;(searcher_PageCompleted);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; searcher.SearchCompleted += &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;EventHandler&lt;/span&gt;&amp;lt;AsyncEventArgs&amp;gt;(searcher_SearchCompleted);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; searcher;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
This would allow me to hook up a couple handlers that would be invoked each time a
page came back or my search was finished.
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Consolas"&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; searcher_SearchCompleted(&lt;span style="COLOR: blue"&gt;object&lt;/span&gt; sender,
AsyncEventArgs e)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;{&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//this
is volatile, so we need check it first or another thread&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//could
change this from under us&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;bool&lt;/span&gt; lastSearch
= (((AsyncSearcher)sender).PendingSearches == 0);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;Console&lt;/span&gt;.WriteLine(&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: maroon"&gt;"{0}
Search Complete on thread {1}"&lt;/span&gt;,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; e.RequestID.Equals(_firstSearch) ? &lt;span style="COLOR: maroon"&gt;"First"&lt;/span&gt; : &lt;span style="COLOR: maroon"&gt;"Second"&lt;/span&gt;,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;Thread&lt;/span&gt;.CurrentThread.ManagedThreadId&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; );&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (lastSearch)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _resetEvent.Set();&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;}&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; searcher_PageCompleted(&lt;span style="COLOR: blue"&gt;object&lt;/span&gt; sender,
AsyncEventArgs e)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;{&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//or
do something with e.Results here...&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;Console&lt;/span&gt;.WriteLine(&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: maroon"&gt;"Found
{0} results on thread {1} for {2} search"&lt;/span&gt;,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; e.Results.Count,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;Thread&lt;/span&gt;.CurrentThread.ManagedThreadId,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; e.RequestID.Equals(_firstSearch) ? &lt;span style="COLOR: maroon"&gt;"first"&lt;/span&gt; : &lt;span style="COLOR: maroon"&gt;"second"&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; );&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
The complication with this model has to do with the fact that I wanted to be able
to use the same object to search multiple times.&amp;nbsp; I could have limited my AsyncSearcher
class to disallow more than one search at a time, but I thought that would be lame
if I had to spin up a new instance and set of handlers for each search I wanted to
perform.&amp;nbsp; Since I could only register for one paging and one completion event
and yet multiple searches could be firing it, I needed a way to distinguish one search
from another.&amp;nbsp; I decided to return a unique Guid for each search that could be
matched up later to determine which search was activating the event.&amp;nbsp; With more
time, I suppose I could have wrapped the Guid in something a little prettier or easier
to use, but it suffices for this sample.
&lt;/p&gt;
&lt;p&gt;
I also decided that I wanted to return results by pages as I got them as well as the
huge block of them on completion of the search.&amp;nbsp; To do this, I created a simple
class to hold the results called AsyncEventArgs:
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Consolas"&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="COLOR: gray"&gt;///&lt;/span&gt;&lt;span style="COLOR: green"&gt; &lt;/span&gt;&lt;span style="COLOR: gray"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="COLOR: gray"&gt;///&lt;/span&gt;&lt;span style="COLOR: green"&gt; Just
a simple class to hold some results&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="COLOR: gray"&gt;///&lt;/span&gt;&lt;span style="COLOR: green"&gt; &lt;/span&gt;&lt;span style="COLOR: gray"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;class&lt;/span&gt; AsyncEventArgs
: &lt;span style="COLOR: teal"&gt;EventArgs&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;{&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;Guid&lt;/span&gt; _id;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;List&lt;/span&gt;&amp;lt;SearchResultEntry&amp;gt;
_entries;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; AsyncEventArgs(&lt;span style="COLOR: teal"&gt;List&lt;/span&gt;&amp;lt;SearchResultEntry&amp;gt;
entries, &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; requestID)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _entries = entries;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _id = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;Guid&lt;/span&gt;(requestID);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: teal"&gt;List&lt;/span&gt;&amp;lt;SearchResultEntry&amp;gt;
Results&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; _entries;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: teal"&gt;Guid&lt;/span&gt; RequestID&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; _id;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
I could have created a different EventArg class depending on the type of event being
fired, but I didn&amp;rsquo;t think it was worth it as this point.&amp;nbsp; Now that I had
how I wanted to use the object nailed down a bit, I created the actual implementation.&amp;nbsp;
The logic goes something like this in:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Setup initial search and kick it off (steps 1&amp;ndash;5 above), register a callback
and pass my SearchRequest as state.&lt;/li&gt;
&lt;li&gt;
Callback now picks up request and unwraps the SearchRequest (which also tells me which
unique search I am after here) and calls LdapConnection.EndSendRequest()&lt;/li&gt;
&lt;li&gt;
Pull the results from the resulting SearchResponse and fire the PageCompleted event
&amp;ndash; passing them as EventArgs&lt;/li&gt;
&lt;li&gt;
Next, determine if the SearchResponse has a cookie and if it does, call BeginSendRequest
again with updated paging cookie and point it back to my original callback (#2).&amp;nbsp;
This means there is a lot of 2 through 4 going on here as each page gets processed
and the PageCompleted event fires.&lt;/li&gt;
&lt;li&gt;
If the cookie in #4 is empty, then I am done and I fire the SearchCompleted event
and pass as EventArgs all the results I have been collecting internally in a hashtable
keyed to the original request Guid.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
Here is what that class looks like:
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Consolas"&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;class&lt;/span&gt; AsyncSearcher&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;{&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; LdapConnection _connect;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;Hashtable&lt;/span&gt; _results
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;Hashtable&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;event&lt;/span&gt; &lt;span style="COLOR: teal"&gt;EventHandler&lt;/span&gt;&amp;lt;AsyncEventArgs&amp;gt;
SearchCompleted;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;event&lt;/span&gt; &lt;span style="COLOR: teal"&gt;EventHandler&lt;/span&gt;&amp;lt;AsyncEventArgs&amp;gt;
PageCompleted;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; AsyncSearcher(LdapConnection
connection)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;._connect
= connection;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;._connect.AutoBind
= &lt;span style="COLOR: blue"&gt;true&lt;/span&gt;; &lt;span style="COLOR: green"&gt;//will bind on
first search&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: gray"&gt;///&lt;/span&gt;&lt;span style="COLOR: green"&gt; &lt;/span&gt;&lt;span style="COLOR: gray"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: gray"&gt;///&lt;/span&gt;&lt;span style="COLOR: green"&gt; Volatile
count of outstanding searches in process&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: gray"&gt;///&lt;/span&gt;&lt;span style="COLOR: green"&gt; &lt;/span&gt;&lt;span style="COLOR: gray"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; PendingSearches&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; _results.Count;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; InternalCallback(&lt;span style="COLOR: teal"&gt;IAsyncResult&lt;/span&gt; result)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SearchResponse response = &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;._connect.EndSendRequest(result) &lt;span style="COLOR: blue"&gt;as&lt;/span&gt; SearchResponse;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ProcessResponse(response, ((SearchRequest)result.AsyncState).RequestId);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//find
the returned page response control&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt; (DirectoryControl
control &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; response.Controls)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (control &lt;span style="COLOR: blue"&gt;is&lt;/span&gt; PageResultResponseControl)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//call
paged search again&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; NextPage((SearchRequest)result.AsyncState, ((PageResultResponseControl)control).Cookie);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;break&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; ProcessResponse(SearchResponse
response, &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; guid)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//only
1 thread at a time gets here...&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;List&lt;/span&gt;&amp;lt;SearchResultEntry&amp;gt;
entries = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;List&lt;/span&gt;&amp;lt;SearchResultEntry&amp;gt;();&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt; (SearchResultEntry
entry &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; response.Entries)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; entries.Add(entry);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//signal
our caller that we have a page&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;EventHandler&lt;/span&gt;&amp;lt;AsyncEventArgs&amp;gt;
OnPage = PageCompleted;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (OnPage
!= &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; OnPage(&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; AsyncEventArgs(entries,
guid)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; );&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//add
to the main collection&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ((&lt;span style="COLOR: teal"&gt;List&lt;/span&gt;&amp;lt;SearchResultEntry&amp;gt;)_results[guid]).AddRange(entries);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: teal"&gt;Guid&lt;/span&gt; BeginPagedSearch(&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; baseDN,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; filter,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt;[]
attribs,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; pageSize&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; )&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;Guid&lt;/span&gt; guid
= &lt;span style="COLOR: teal"&gt;Guid&lt;/span&gt;.NewGuid();&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SearchRequest request = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; SearchRequest(&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; baseDN,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; filter,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; System.DirectoryServices.Protocols.SearchScope.Subtree,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; attribs&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; );&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; PageResultRequestControl prc = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; PageResultRequestControl(pageSize);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//add
the paging control&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; request.Controls.Add(prc);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//we
will use this to distinguish multiple searches.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; request.RequestId = guid.ToString();&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//create
a temporary placeholder for the results&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _results.Add(request.RequestId, &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;List&lt;/span&gt;&amp;lt;SearchResultEntry&amp;gt;());&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//kick
off async&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;IAsyncResult&lt;/span&gt; result
= &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;._connect.BeginSendRequest(&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; request,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; PartialResultProcessing.NoPartialResultSupport,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;AsyncCallback&lt;/span&gt;(InternalCallback),&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; request&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; );&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; guid;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; NextPage(SearchRequest
request, &lt;span style="COLOR: blue"&gt;byte&lt;/span&gt;[] cookie)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//our
last page is when the cookie is empty&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (cookie
!= &lt;span style="COLOR: blue"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; cookie.Length != 0)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//update
the cookie and preserve page size&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt; (DirectoryControl
control &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; request.Controls)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (control &lt;span style="COLOR: blue"&gt;is&lt;/span&gt; PageResultRequestControl)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ((PageResultRequestControl)control).Cookie = cookie;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;break&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//call
it again to get next page&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;IAsyncResult&lt;/span&gt; result
= &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;._connect.BeginSendRequest(&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; request,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; PartialResultProcessing.NoPartialResultSupport,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;AsyncCallback&lt;/span&gt;(InternalCallback),&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; request&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; );&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;List&lt;/span&gt;&amp;lt;SearchResultEntry&amp;gt;
results = (&lt;span style="COLOR: teal"&gt;List&lt;/span&gt;&amp;lt;SearchResultEntry&amp;gt;)_results[request.RequestId];&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//decrement
our collection when we are done&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _results.Remove(request.RequestId);&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//we
have finished, signal the caller&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;EventHandler&lt;/span&gt;&amp;lt;AsyncEventArgs&amp;gt;
OnComplete = SearchCompleted;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (OnComplete
!= &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; OnComplete(&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;,&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; AsyncEventArgs(results,
request.RequestId)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; );&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
I originally toyed with the idea of having the AsyncSearcher manage the connection
to the directory, but ultimately decided that it was a bad idea for two main reasons.&amp;nbsp;
First, not everyone will construct the connection the same.&amp;nbsp; Some people will
use SSPI, others SSL, perhaps different ports, even certificates or otherwise.&amp;nbsp;
The other reason is that the lifetime of the connection is harder to control from
inside another class.&amp;nbsp; Wrapping it in a &amp;ldquo;using&amp;rdquo; statement won&amp;rsquo;t
work because the connection must be open the whole time during the callbacks.&amp;nbsp;
Cleaning it up in a Dispose() method is sloppy as well because it leads to the client
needing to know that they should keep this object around until all their events fire.&amp;nbsp;
By pulling the LdapConnection out, I am implicitly telling clients they need to manage
the connection themselves.
&lt;/p&gt;
&lt;p&gt;
You can download this class along with a sample client&amp;nbsp;as an attachment to this
post.&amp;nbsp; Next time, perhaps we will delve into retrieving partial results.
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&lt;a href="http://dunnry.com/blog/content/binary/AsynchClient.zip"&gt;File Attachment:
AsynchClient.zip (5 KB)&lt;/a&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=96398858-4504-45f0-bc84-c4ea18c1f9a9" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,96398858-4504-45f0-bc84-c4ea18c1f9a9.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
      <category>Protocols</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=bf18b65d-ab5a-4b58-a40c-9756a3f859e4</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,bf18b65d-ab5a-4b58-a40c-9756a3f859e4.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,bf18b65d-ab5a-4b58-a40c-9756a3f859e4.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=bf18b65d-ab5a-4b58-a40c-9756a3f859e4</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
One of my co-workers forwarded this link to me today.  Essentially, it is <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=89E6B1E5-F66C-4A4D-933B-46222BB01EB0&amp;displaylang=en">XSDObjectGen</a> for
2.0 with support for things like partial classes, generics, etc.  We tend to
use this as a basis for our service contracts and to help serialize outward facing
DTO objects.  I was looking for something similar (or the source to XSDObjectGen
to do it myself) a few months back.  Very cool.
</p>
        <p>
Get it here:
</p>
        <p>
          <a href="http://devauthority.com/blogs/ram_marappan/archive/2006/10/03/4755.aspx">http://devauthority.com/blogs/ram_marappan/archive/2006/10/03/4755.aspx</a>
        </p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=bf18b65d-ab5a-4b58-a40c-9756a3f859e4" />
      </body>
      <title>XSD Object Generation for .NET 2.0</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,bf18b65d-ab5a-4b58-a40c-9756a3f859e4.aspx</guid>
      <link>http://dunnry.com/blog/2006/10/12/XSDObjectGenerationForNET20.aspx</link>
      <pubDate>Thu, 12 Oct 2006 17:43:08 GMT</pubDate>
      <description>&lt;p&gt;
One of my co-workers forwarded this link to me today.&amp;nbsp; Essentially, it is &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=89E6B1E5-F66C-4A4D-933B-46222BB01EB0&amp;amp;displaylang=en"&gt;XSDObjectGen&lt;/a&gt; for
2.0 with support for things like partial classes, generics, etc.&amp;nbsp; We tend to
use this as a basis for our service contracts and to help serialize outward facing
DTO objects.&amp;nbsp; I was looking for something similar (or the source to XSDObjectGen
to do it myself) a few months back.&amp;nbsp;&amp;nbsp;Very cool.
&lt;/p&gt;
&lt;p&gt;
Get it here:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://devauthority.com/blogs/ram_marappan/archive/2006/10/03/4755.aspx"&gt;http://devauthority.com/blogs/ram_marappan/archive/2006/10/03/4755.aspx&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=bf18b65d-ab5a-4b58-a40c-9756a3f859e4" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,bf18b65d-ab5a-4b58-a40c-9756a3f859e4.aspx</comments>
      <category>.NET</category>
      <category>Design</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=8de76e8d-48b9-48eb-ac4a-11929730c9a5</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,8de76e8d-48b9-48eb-ac4a-11929730c9a5.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,8de76e8d-48b9-48eb-ac4a-11929730c9a5.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=8de76e8d-48b9-48eb-ac4a-11929730c9a5</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <title>MVP Again</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,8de76e8d-48b9-48eb-ac4a-11929730c9a5.aspx</guid>
      <link>http://dunnry.com/blog/2006/10/04/MVPAgain.aspx</link>
      <pubDate>Wed, 04 Oct 2006 13:17:44 GMT</pubDate>
      <description>&lt;p&gt;
I was fortunate enough to receive the MVP award again for the 2007 year.&amp;nbsp; I would
like to thank Microsoft and all the program supporters that make this possible.&amp;nbsp;
I enjoy helping others and that is why I do it &amp;ndash; the MVP privileges however
are a very nice perk.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=8de76e8d-48b9-48eb-ac4a-11929730c9a5" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,8de76e8d-48b9-48eb-ac4a-11929730c9a5.aspx</comments>
      <category>.NET</category>
      <category>MVP</category>
      <category>Personal</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=16d95e7f-579a-4da8-bf63-d74dcf6714d5</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,16d95e7f-579a-4da8-bf63-d74dcf6714d5.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,16d95e7f-579a-4da8-bf63-d74dcf6714d5.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=16d95e7f-579a-4da8-bf63-d74dcf6714d5</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <title>I'm a Dork</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,16d95e7f-579a-4da8-bf63-d74dcf6714d5.aspx</guid>
      <link>http://dunnry.com/blog/2006/08/20/ImADork.aspx</link>
      <pubDate>Sun, 20 Aug 2006 21:55:24 GMT</pubDate>
      <description>Joe Richards, of &lt;a href="http://www.amazon.com/gp/redirect.html?link_code=ur2&amp;amp;tag=extemporaneou-20&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;location=%2Fgp%2Fproduct%2F0596101732%2F"&gt;Active
Directory 3rd Edition&lt;/a&gt; fame was nice enough to label me here as one of his &amp;lsquo;&lt;a href="http://blog.joeware.net/2006/08/14/525/"&gt;dorks&lt;/a&gt;&amp;rsquo;.&amp;nbsp;
His book, btw is one of the best (if not the best) references to Active Directory.&amp;nbsp;
Thanks Joe.&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=16d95e7f-579a-4da8-bf63-d74dcf6714d5" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,16d95e7f-579a-4da8-bf63-d74dcf6714d5.aspx</comments>
      <category>.NET</category>
      <category>Personal</category>
      <category>MVP</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=1a320076-330c-41b0-99fb-cefd79d4eed0</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,1a320076-330c-41b0-99fb-cefd79d4eed0.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,1a320076-330c-41b0-99fb-cefd79d4eed0.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=1a320076-330c-41b0-99fb-cefd79d4eed0</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <title>Fast Concurrent Binding in SDS.P</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,1a320076-330c-41b0-99fb-cefd79d4eed0.aspx</guid>
      <link>http://dunnry.com/blog/2006/08/04/FastConcurrentBindingInSDSP.aspx</link>
      <pubDate>Fri, 04 Aug 2006 15:21:17 GMT</pubDate>
      <description>&lt;p&gt;
So, this is really a lesson learned about putting together a book and code samples.&amp;nbsp;
Namely, refactoring your code just before the final cut is generally not a good idea.&amp;nbsp;
Or perhaps I should say, refactoring your code and not thoroughly testing it is not
a good idea.
&lt;/p&gt;
&lt;p&gt;
In Chapter 12 of &lt;a href="http://www.amazon.com/exec/obidos/redirect?link_code=ur2&amp;amp;tag=extemporaneou-20&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;path=http%3A%2F%2Fwww.amazon.com%2Fgp%2Fproduct%2F0321350170%2F"&gt;the
book&lt;/a&gt;, we had a number of examples for how to perform authentication.&amp;nbsp; One
of them was using System.DirectoryServices.Protocols (SDS.P).&amp;nbsp; The sample tried
a number of techniques &amp;ndash; first a secure SSL bind using Fast Concurrent Binding
(FCB), then it tried either a secure SPNEGO bind or a Digest bind (if ADAM).&amp;nbsp;
Well, initially these were all different samples.&amp;nbsp; I thought it might be nice
to tie them all together a bit more comprehensively &amp;ndash; hence the refactoring.&amp;nbsp;
I figured that a bigger sample that did more in a practical manner was more useful
than a few line snippets that showed each one.
&lt;/p&gt;
&lt;p&gt;
Anyhow, what ended up happening is that I broke the FCB authentication during the
refactoring.&amp;nbsp; Because of unforseen testing environment meltdown a week earlier
I did not have the proper Win2k3 clients to test again (it used to work, really!).&amp;nbsp;
So&amp;hellip; I borked it because the FCB code never got tested again.
&lt;/p&gt;
&lt;p&gt;
One of my Avanade co-workers was actually implementing something like this and asked
why it was not working.&amp;nbsp; At first I chalked it up to an environment thing, but
after a closer inspection I noticed what the issue was.&amp;nbsp; Namely, in my attempt
to bring all the samples together&amp;nbsp;I had attempted to reuse the same connection
for authentication as the bootstrapping.&amp;nbsp; Well, you can&amp;rsquo;t do that with
FCB &amp;ndash; you have to enable it before you bind and cannot turn it off until you
close the connection.
&lt;/p&gt;
&lt;p&gt;
The good news is that it is a fairly simple fix and I have already refactored (yet
again) to support it.&amp;nbsp; I will be posting that code in another week or so when
I get back from vacation.&amp;nbsp; Then &lt;a href="http://www.joekaplan.net/"&gt;poor Joe&lt;/a&gt; gets
to convert it yet again to VB.NET.&amp;nbsp; Mea Culpa&amp;hellip;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=1a320076-330c-41b0-99fb-cefd79d4eed0" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,1a320076-330c-41b0-99fb-cefd79d4eed0.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
      <category>Book</category>
      <category>Protocols</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=acfcadfe-58b2-42bb-99d1-c121fe2381f0</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,acfcadfe-58b2-42bb-99d1-c121fe2381f0.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,acfcadfe-58b2-42bb-99d1-c121fe2381f0.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=acfcadfe-58b2-42bb-99d1-c121fe2381f0</wfw:commentRss>
      <title>More SDS Bloggers</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,acfcadfe-58b2-42bb-99d1-c121fe2381f0.aspx</guid>
      <link>http://dunnry.com/blog/2006/08/04/MoreSDSBloggers.aspx</link>
      <pubDate>Fri, 04 Aug 2006 14:47:20 GMT</pubDate>
      <description>My co-author &lt;a href="http://www.joekaplan.net/"&gt;Joe Kaplan&lt;/a&gt; is finally online
and blogging now.&amp;nbsp; I have asked him for more Wix content since he knows a bunch
more than me on it.&amp;nbsp; More LDAP blogging goodness to come I am sure&amp;hellip;&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=acfcadfe-58b2-42bb-99d1-c121fe2381f0" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,acfcadfe-58b2-42bb-99d1-c121fe2381f0.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
      <category>Book</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=23e5171d-5fcc-4452-ad54-c47a1b96d72d</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,23e5171d-5fcc-4452-ad54-c47a1b96d72d.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,23e5171d-5fcc-4452-ad54-c47a1b96d72d.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=23e5171d-5fcc-4452-ad54-c47a1b96d72d</wfw:commentRss>
      <title>msDs-User-Account-Control-Computed Not So Spiffy</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,23e5171d-5fcc-4452-ad54-c47a1b96d72d.aspx</guid>
      <link>http://dunnry.com/blog/2006/07/27/msDsUserAccountControlComputedNotSoSpiffy.aspx</link>
      <pubDate>Thu, 27 Jul 2006 12:33:32 GMT</pubDate>
      <description>&lt;p&gt;
You learn something new everyday.&amp;nbsp; I had been under the mistaken belief that
the new &amp;lsquo;msDs-User-Account-Control-Computed&amp;rsquo; attribute was a sexier and
more accurate version of the older, non-constructed &amp;lsquo;userAccountControl&amp;rsquo;.&amp;nbsp;
In fact, I believe it might have been me that wrote words to that effect in the &lt;a href="http://directoryprogramming.net/"&gt;book&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Yeah&amp;hellip; well&amp;hellip; whoops.&amp;nbsp; An errata post is coming.
&lt;/p&gt;
&lt;p&gt;
If we recap what we did not like about &amp;lsquo;userAccountControl&amp;rsquo; it was that
it did not accurately reflect all the user flags (PasswordExpired, PasswordCannotChange,
and AccountLockout specifically) for the LDAP provider.&amp;nbsp; It would seem natural
that the &amp;lsquo;msDs-User-Account-Control-Computed&amp;rsquo; attribute was identical
to the &amp;lsquo;userAccountControl&amp;rsquo; attribute, but also accurately reflected those
3 flags.&amp;nbsp; At least for Active Directory, this is just not true.&amp;nbsp; It turns
out that this sucker will be zero for everything except AccountLockout and PasswordExpired.&amp;nbsp;
Boo, hiss&amp;hellip;
&lt;/p&gt;
&lt;p&gt;
So, what seemed like a promising replacement for an all-in-one user flags smorgasbord,
is in fact a bit of an anorexic turd.&amp;nbsp; Why MS chose this particular behavior
is beyond me&amp;hellip;
&lt;/p&gt;
&lt;p&gt;
The moral of the story?&amp;nbsp; You are still stuck with using both attributes &amp;ndash;
and even then you can&amp;rsquo;t get an accurate PasswordCannotChange flag.&amp;nbsp; Bummer.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=23e5171d-5fcc-4452-ad54-c47a1b96d72d" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,23e5171d-5fcc-4452-ad54-c47a1b96d72d.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=c90916cd-a47a-4de9-be6f-141ce8883e9a</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,c90916cd-a47a-4de9-be6f-141ce8883e9a.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,c90916cd-a47a-4de9-be6f-141ce8883e9a.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c90916cd-a47a-4de9-be6f-141ce8883e9a</wfw:commentRss>
      <title>A Recursive Pattern For DN Syntax Attributes Part 2</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,c90916cd-a47a-4de9-be6f-141ce8883e9a.aspx</guid>
      <link>http://dunnry.com/blog/2006/07/24/ARecursivePatternForDNSyntaxAttributesPart2.aspx</link>
      <pubDate>Mon, 24 Jul 2006 19:12:52 GMT</pubDate>
      <description>&lt;p&gt;
I am revisiting this particular topic once again to finish it up.&amp;nbsp; &lt;a href="http://dunnry.com/blog/ARecursivePatternForDNSyntaxAttributes.aspx"&gt;Last
time&lt;/a&gt;, we established a general pattern for searching any DN syntax attribute in
Active Directory or ADAM and chasing down all the nested results in either direction
(i.e. forward link to back link or vice versa).&amp;nbsp; The solution worked well with
one caveat:&amp;nbsp; intermediate values.&amp;nbsp; We often do not want to capture the intermediate
values, but only the end results.&amp;nbsp; As an example, if we were to expand the group
membership for a group object (the &amp;lsquo;member&amp;rsquo; attribute) to discover the
users, we would not want to include the other nested groups as values in our results,
but we would only want to include the users in those nested groups.&amp;nbsp; In other
words, we would want to exclude the intermediate values.&amp;nbsp; This is different than
another example, say of discovering an org chart by expanding the &amp;lsquo;directReports&amp;rsquo;
attribute where we would clearly want to know all the intermediate reports.
&lt;/p&gt;
&lt;p&gt;
For the specific example of expanding a group object to get membership, I posted &lt;a href="http://directoryprogramming.net/files"&gt;an
example&lt;/a&gt; in the book that used recursion and specifically excluded the result if
the &amp;lsquo;objectClass&amp;rsquo; was &amp;lsquo;group&amp;rsquo;.&amp;nbsp; I posed the question,
&amp;ldquo;was this necessary?&amp;rdquo;.&amp;nbsp; Or more specifically, &amp;ldquo;can we create
a general solution that will deal with both cases for intermediate values?&amp;rdquo;
&lt;/p&gt;
&lt;p&gt;
The answer, of course, is yes.&amp;nbsp; We can pretty easily create a solution that will
allow us to keep the intermediate values or discard them if we want.&amp;nbsp; In the
general case, we do not need to know the object types.&amp;nbsp; In our example in the
book, I think it was more clear what was happening by putting knowledge of the object
type.&amp;nbsp; However,&amp;nbsp;it also could have been solved with a&amp;nbsp;simple boolean
and no knowledge of the objects themselves.&amp;nbsp; Here is the revised solution.&amp;nbsp;
I am omitting the IADsPathname interface this time, but you can easily pull it from
the last post.
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Consolas"&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Consolas"&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;class&lt;/span&gt; RecursiveLinkPair
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; DirectoryEntry entry;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ArrayList members;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Hashtable processed;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; attrib;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;bool&lt;/span&gt; includeAll;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; RecursiveLinkPair(DirectoryEntry
entry, &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; attrib, &lt;span style="COLOR: blue"&gt;bool&lt;/span&gt; includeIntermediate)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (entry == &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;throw&lt;/span&gt; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style="COLOR: maroon"&gt;"entry"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (String.IsNullOrEmpty(attrib))
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;throw&lt;/span&gt; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; ArgumentException(&lt;span style="COLOR: maroon"&gt;"attrib"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.includeAll
= includeIntermediate;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.attrib
= attrib;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.entry
= entry;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.processed
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; Hashtable();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.processed.Add(
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.entry.Properties[
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: maroon"&gt;"distinguishedName"&lt;/span&gt;][0].ToString(),
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; );
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.members
= Expand(&lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.entry);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; ArrayList Members
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;get&lt;/span&gt; { &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.members;
}
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; ArrayList Expand(DirectoryEntry
group)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ArrayList al = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; ArrayList(5000);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; DirectorySearcher ds = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; DirectorySearcher(
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; entry,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: maroon"&gt;"(objectClass=*)"&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt;[]
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.attrib,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: maroon"&gt;"distinguishedName"&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: maroon"&gt;"objectClass"&lt;/span&gt; },
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SearchScope.Base
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; );
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ds.AttributeScopeQuery = &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.attrib;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ds.PageSize = 1000;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;using&lt;/span&gt; (SearchResultCollection
src = ds.FindAll())
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; dn
= &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt; (SearchResult
sr &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; src)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; dn = (&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
sr.Properties[&lt;span style="COLOR: maroon"&gt;"distinguishedName"&lt;/span&gt;][0];
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (!&lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.processed.ContainsKey(dn))
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.processed.Add(dn, &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (sr.Properties.Contains(&lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.attrib))
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.includeAll)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; al.Add(dn);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; SetNewPath(&lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.entry, dn);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; al.AddRange(Expand(&lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.entry));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
}
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;else&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; al.Add(dn);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; al;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//we will use IADsPathName utility function
instead&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//of parsing string values.&amp;nbsp; This
particular function&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//allows us to replace only the DN portion
of a path&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//and leave the server and port information
intact&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; SetNewPath(DirectoryEntry
entry, &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; dn)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; IAdsPathname pathCracker = (IAdsPathname)&lt;span style="COLOR: blue"&gt;new&lt;/span&gt; Pathname();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; pathCracker.Set(entry.Path, 1);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; pathCracker.Set(dn, 4);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; entry.Path = pathCracker.Retrieve(5);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
This simple class uses the AttributeScopeQuery option to enumerate the attribute and
then uses the utility interface IADsPathname to reset the entry as we recurse the
results.&amp;nbsp; So, we now finally have a generic solution that will work on all DN
syntax attributes in both directions and with or without intermediate values.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=c90916cd-a47a-4de9-be6f-141ce8883e9a" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,c90916cd-a47a-4de9-be6f-141ce8883e9a.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
      <category>Groups</category>
      <category>Tips</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=d9be43d8-efa0-4680-a894-2d87900434b6</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,d9be43d8-efa0-4680-a894-2d87900434b6.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,d9be43d8-efa0-4680-a894-2d87900434b6.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=d9be43d8-efa0-4680-a894-2d87900434b6</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
A common task that any Active Directory developer will face is to expand group membership
for a given group.  This is a trivially simple task if we are only interested
in finding direct group membership.  Things can get much more complicated when
nested or indirect group membership is also involved.  Consider the following:
</p>
        <p>
Group A: members – “Timmy”, “Alice”, “Bob”, “Group B”
</p>
        <p>
Group B: members – “Jake”, “Jimmy”, “Nelson”
</p>
        <p>
If we wanted to fully expand the group membership of Group A, we would expect to see
6 users in this case.  The issue of course is that the membership for a group
is held on the ‘member’ attribute.  If we were to inspect this attribute directly,
we would see only 4 members, with one of them being ‘Group B’.  The problem of
course is that we cannot tell just by looking at the ‘member’ attribute which one
is a group and which ones are the object types we are interested in (in this case
user objects).  Short of a naming convention to indicate which is a group, we
would have to bind or search for each object and determine if it was a group in
order to continue the search.  This is how it is done today using .NET 1.x. 
In fact – you can find an example of this by reading Chapter 11 and specifically viewing
Listing 11.7.  I am also glossing over a couple details for 1.x regarding large
DN-syntax attributes – but you can read about that of course in Chapter 11 <img src="http://www.dunnry.com/blog/smile1.gif" />. 
I also won’t post the code for expanding group membership using recursion in 2.0 because
that code is already available for download from the <a href="http://directoryprogramming.net/">book’s
companion website </a>(Listing 11.6).  However, I will talk about this as a basis
to discover a more general pattern.
</p>
        <p>
Introduced with Windows 2003 and available to .NET 2.0 users is a new type of
search called Attribute Scoped Query (ASQ).  An ASQ allows us to scope our searches
to any DN-syntax attribute.  This powerful feature is ideal for things like membership
expansion, or indeed, any DN-syntax attribute that should be expanded.  By scoping
our search on the DN, we can easily overcome some of the limitations in other methods
(such as range retrieval), which leads to a simpler conceptual model.
</p>
        <p>
Another example where we would want to expand DN-syntax attributes occurs when we
are checking for employees managed directly and indirectly by a particular individual. 
For instance, we might have an employee that manages 1 employee that in turn manages
15 other employees.  It is fair to say in most organizations that the first employee
really manages 16 employees rather than just one.  We have to use recursion however
to fully expand this relationship.  The employee carries their manager’s DN on
the attribute ‘manager’, while the manager has a backlink to the employee on the ‘directReports’
attribute.  This is a similar class of problem as the group membership expansion.
</p>
        <p>
If we look at these two examples, we should notice some similarities and some key
differences.  In both cases, we have the DN of another object to describe the
relationship.  In both cases, we need to chase that DN to see if it in turn references
other DNs.  However, there are two key differences.  First, in the case
of group membership, we don’t care to see the intermediate results (e.g. Group B),
but only the fully expanded members.  Next, for group membership, we are chasing
a multi-valued forward link (the ‘member’ attribute), while in the employee example,
we are chasing the backlink (the ‘directReports’ attribute).  The question we
should consider is whether these differences will change our pattern.  They would
be almost identical problems if the employee was trying to figure out all their bosses,
or the user was trying to determine all their group memberships.
</p>
        <p>
&lt;Jeopardy music playing&gt; So, do the two differences matter?  What if the
forward link is single-valued (‘manager’ as opposed to ‘member’ for example)? &lt;/Jeopardy
music playing&gt;
</p>
        <p>
The answer is yes and no.  The problem with excluding intermediate results certainly
must be accounted for, but whether or not it is the backlink or forward link actually
has no bearing on the problem.  It turns out that ASQ searches work just fine
with DN-syntax attributes of either type – even when the forward link is single-valued.
</p>
        <p>
Ignoring the intermediate value issue for now, we can produce a generalized solution
for any DN-syntax recursion:
</p>
        <pre style="border: 1pt solid windowtext; padding: 0pt; background: white none repeat scroll 0%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: Consolas;">
          <span style="color: blue;">public</span>
          <span style="color: blue;">class</span> RecursiveLinkPair
{ DirectoryEntry entry; ArrayList members; Hashtable processed; <span style="color: blue;">string</span> attrib; <span style="color: blue;">public</span> RecursiveLinkPair(DirectoryEntry
entry, <span style="color: blue;">string</span> attrib) { <span style="color: blue;">if</span> (entry
== <span style="color: blue;">null</span>) <span style="color: blue;">throw</span><span style="color: blue;">new</span> ArgumentNullException("entry"); <span style="color: blue;">if</span> (String.IsNullOrEmpty(attrib)) <span style="color: blue;">throw</span><span style="color: blue;">new</span> ArgumentException("attrib"); <span style="color: blue;">this</span>.attrib
= attrib; <span style="color: blue;">this</span>.entry = entry; <span style="color: blue;">this</span>.processed
= <span style="color: blue;">new</span> Hashtable(); <span style="color: blue;">this</span>.processed.Add( <span style="color: blue;">this</span>.entry.Properties[
"distinguishedName"][0].ToString(), <span style="color: blue;">null</span> ); <span style="color: blue;">this</span>.members
= Expand(<span style="color: blue;">this</span>.entry); } <span style="color: blue;">public</span> ArrayList
Members { <span style="color: blue;">get</span> { <span style="color: blue;">return</span><span style="color: blue;">this</span>.members;
} } <span style="color: blue;">private</span> ArrayList Expand(DirectoryEntry group)
{ ArrayList al = <span style="color: blue;">new</span> ArrayList(5000); DirectorySearcher
ds = <span style="color: blue;">new</span> DirectorySearcher( entry, "(objectClass=*)", <span style="color: blue;">new</span><span style="color: blue;">string</span>[]
{ <span style="color: blue;">this</span>.attrib, "distinguishedName" }, SearchScope.Base
); ds.AttributeScopeQuery = <span style="color: blue;">this</span>.attrib; ds.PageSize
= 1000; <span style="color: blue;">using</span> (SearchResultCollection src = ds.FindAll())
{ <span style="color: blue;">string</span> dn = <span style="color: blue;">null</span>; <span style="color: blue;">foreach</span> (SearchResult
sr <span style="color: blue;">in</span> src) { dn = (<span style="color: blue;">string</span>)
sr.Properties["distinguishedName"][0]; <span style="color: blue;">if</span> (!<span style="color: blue;">this</span>.processed.ContainsKey(dn))
{ <span style="color: blue;">this</span>.processed.Add(dn, <span style="color: blue;">null</span>);
al.Add(dn); <span style="color: blue;">if</span> (sr.Properties.Contains(<span style="color: blue;">this</span>.attrib))
{ SetNewPath(<span style="color: blue;">this</span>.entry, dn); al.AddRange(Expand(<span style="color: blue;">this</span>.entry));
} } } } <span style="color: blue;">return</span> al; } <span style="color: green;">//we
will use IADsPathName utility function instead</span><span style="color: green;">//of
parsing string values. This particular function</span><span style="color: green;">//allows
us to replace only the DN portion of a path</span><span style="color: green;">//and
leave the server and port information intact</span><span style="color: blue;">private</span><span style="color: blue;">void</span> SetNewPath(DirectoryEntry
entry, <span style="color: blue;">string</span> dn) { IAdsPathname pathCracker = (IAdsPathname)<span style="color: blue;">new</span> Pathname();
pathCracker.Set(entry.Path, 1); pathCracker.Set(dn, 4); entry.Path = pathCracker.Retrieve(5);
} } [ComImport, Guid("D592AED4-F420-11D0-A36E-00C04FB950DC"), InterfaceType(ComInterfaceType.InterfaceIsDual)] <span style="color: blue;">internal</span><span style="color: blue;">interface</span> IAdsPathname
{ [SuppressUnmanagedCodeSecurity] <span style="color: blue;">int</span> Set([In, MarshalAs(UnmanagedType.BStr)] <span style="color: blue;">string</span> bstrADsPath,
[In, MarshalAs(UnmanagedType.U4)] <span style="color: blue;">int</span> lnSetType); <span style="color: blue;">int</span> SetDisplayType([In,
MarshalAs(UnmanagedType.U4)] <span style="color: blue;">int</span> lnDisplayType);
[<span style="color: blue;">return</span>: MarshalAs(UnmanagedType.BStr)] [SuppressUnmanagedCodeSecurity] <span style="color: blue;">string</span> Retrieve([In,
MarshalAs(UnmanagedType.U4)] <span style="color: blue;">int</span> lnFormatType);
[<span style="color: blue;">return</span>: MarshalAs(UnmanagedType.U4)] <span style="color: blue;">int</span> GetNumElements();
[<span style="color: blue;">return</span>: MarshalAs(UnmanagedType.BStr)] <span style="color: blue;">string</span> GetElement([In,
MarshalAs(UnmanagedType.U4)] <span style="color: blue;">int</span> lnElementIndex); <span style="color: blue;">void</span> AddLeafElement([In,
MarshalAs(UnmanagedType.BStr)] <span style="color: blue;">string</span> bstrLeafElement); <span style="color: blue;">void</span> RemoveLeafElement();
[<span style="color: blue;">return</span>: MarshalAs(UnmanagedType.Interface)] <span style="color: blue;">object</span> CopyPath();
[<span style="color: blue;">return</span>: MarshalAs(UnmanagedType.BStr)] [SuppressUnmanagedCodeSecurity] <span style="color: blue;">string</span> GetEscapedElement([In,
MarshalAs(UnmanagedType.U4)] <span style="color: blue;">int</span> lnReserved, [In,
MarshalAs(UnmanagedType.BStr)] <span style="color: blue;">string</span> bstrInStr); <span style="color: blue;">int</span> EscapedMode
{ <span style="color: blue;">get</span>; [SuppressUnmanagedCodeSecurity] <span style="color: blue;">set</span>;
} } [ComImport, Guid("080d0d78-f421-11d0-a36e-00c04fb950dc")] <span style="color: blue;">internal</span><span style="color: blue;">class</span> Pathname
{ } </pre>
        <!--EndFragment-->
        <!--EndFragment-->
        <p>
Notice I am using the IADsPathName utility interface here.  Since recursion requires
us to re-base our search each time, we need to robustly update our DirectoryEntry
instance’s .Path each time.  This interface does a much better job than trying
to write your own string parsing routines - especially when you need to preserve server
and port information for things like ADAM.  Whenever you see interfaces like
this, check to make sure someone hasn’t already done the setup work
for you.  You can check the .NET framework or ActiveDs interop assembly using Reflector
and find the declaration oftentimes.
</p>
        <p>
The final issue we must deal with now is the problem of intermediate values – specifically
how to exclude them.  I am going to leave that exercise to the reader with just
a hint:
</p>
        <ul>
          <li>
I only included 2 attributes in each search.  If you have already seen my
solution for Group Expansion in the book (Listing 11.6), you will notice that I make
use of a 3rd attribute (objectClass).  Did I need to?</li>
        </ul>
        <p>
Well, this is a long enough post for now.  Signing off…
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=d9be43d8-efa0-4680-a894-2d87900434b6" />
      </body>
      <title>A Recursive Pattern For DN-Syntax Attributes</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,d9be43d8-efa0-4680-a894-2d87900434b6.aspx</guid>
      <link>http://dunnry.com/blog/2006/05/31/ARecursivePatternForDNSyntaxAttributes.aspx</link>
      <pubDate>Wed, 31 May 2006 14:16:19 GMT</pubDate>
      <description>&lt;p&gt;
A common task that any Active Directory developer will face is to expand group membership
for a given group.&amp;nbsp; This is a trivially simple task if we are only interested
in finding direct group membership.&amp;nbsp; Things can get much more complicated when
nested or indirect group membership is also involved.&amp;nbsp; Consider the following:
&lt;/p&gt;
&lt;p&gt;
Group A: members – “Timmy”, “Alice”, “Bob”, “Group B”
&lt;/p&gt;
&lt;p&gt;
Group B: members – “Jake”, “Jimmy”, “Nelson”
&lt;/p&gt;
&lt;p&gt;
If we wanted to fully expand the group membership of Group A, we would expect to see
6 users in this case.&amp;nbsp; The issue of course is that the membership for a group
is held on the ‘member’ attribute.&amp;nbsp; If we were to inspect this attribute directly,
we would see only 4 members, with one of them being ‘Group B’.&amp;nbsp; The problem of
course is that we cannot tell just by looking at the ‘member’ attribute which one
is a group and which ones are the object types we are interested in (in this case
user objects).&amp;nbsp; Short of a naming convention to indicate which is a group, we
would have to bind or search for each object and determine if it was&amp;nbsp;a group&amp;nbsp;in
order to continue the search.&amp;nbsp; This is how it is done today using .NET 1.x.&amp;nbsp;
In fact – you can find an example of this by reading Chapter 11 and specifically viewing
Listing 11.7.&amp;nbsp; I am also glossing over a couple details for 1.x regarding large
DN-syntax attributes – but you can read about that of course in Chapter 11 &lt;img src="http://www.dunnry.com/blog/smile1.gif"&gt;.&amp;nbsp;
I also won’t post the code for expanding group membership using recursion in 2.0 because
that code is already available for download from the &lt;a href="http://directoryprogramming.net/"&gt;book’s
companion website &lt;/a&gt;(Listing 11.6).&amp;nbsp; However, I will talk about this as a basis
to discover a more general pattern.
&lt;/p&gt;
&lt;p&gt;
Introduced with Windows 2003 and available to .NET 2.0 users&amp;nbsp;is a new type of
search called Attribute Scoped Query (ASQ).&amp;nbsp; An ASQ allows us to scope our searches
to any DN-syntax attribute.&amp;nbsp; This powerful feature is ideal for things like membership
expansion, or indeed, any DN-syntax attribute that should be expanded.&amp;nbsp; By scoping
our search on the DN, we can easily overcome some of the limitations in other methods
(such as range retrieval), which leads to a simpler conceptual model.
&lt;/p&gt;
&lt;p&gt;
Another example where we would want to expand DN-syntax attributes occurs when we
are checking for employees managed directly and indirectly by a particular individual.&amp;nbsp;
For instance, we might have an employee that manages 1 employee that in turn manages
15 other employees.&amp;nbsp; It is fair to say in most organizations that the first employee
really manages 16 employees rather than just one.&amp;nbsp; We have to use recursion however
to fully expand this relationship.&amp;nbsp; The employee carries their manager’s DN on
the attribute ‘manager’, while the manager has a backlink to the employee on the ‘directReports’
attribute.&amp;nbsp; This is a similar class of problem as the group membership expansion.
&lt;/p&gt;
&lt;p&gt;
If we look at these two examples, we should notice some similarities and some key
differences.&amp;nbsp; In both cases, we have the DN of another object to describe the
relationship.&amp;nbsp; In both cases, we need to chase that DN to see if it in turn references
other DNs.&amp;nbsp; However, there are two key differences.&amp;nbsp; First, in the case
of group membership, we don’t care to see the intermediate results (e.g. Group B),
but only the fully expanded members.&amp;nbsp; Next, for group membership, we are chasing
a multi-valued forward link (the ‘member’ attribute), while in the employee example,
we are chasing the backlink (the ‘directReports’ attribute).&amp;nbsp; The question we
should consider is whether these differences will change our pattern.&amp;nbsp; They would
be almost identical problems if the employee was trying to figure out all their bosses,
or the user was trying to determine all their group memberships.
&lt;/p&gt;
&lt;p&gt;
&amp;lt;Jeopardy music playing&amp;gt; So, do the two differences matter?&amp;nbsp; What if the
forward link is single-valued (‘manager’ as opposed to ‘member’ for example)? &amp;lt;/Jeopardy
music playing&amp;gt;
&lt;/p&gt;
&lt;p&gt;
The answer is yes and no.&amp;nbsp; The problem with excluding intermediate results certainly
must be accounted for, but whether or not it is the backlink or forward link actually
has no bearing on the problem.&amp;nbsp; It turns out that ASQ searches work just fine
with DN-syntax attributes of either type – even when the forward link is single-valued.
&lt;/p&gt;
&lt;p&gt;
Ignoring the intermediate value issue for now, we can produce a generalized solution
for any DN-syntax recursion:
&lt;/p&gt;
&lt;pre style="border: 1pt solid windowtext; padding: 0pt; background: white none repeat scroll 0%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: Consolas;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; RecursiveLinkPair
{ DirectoryEntry entry; ArrayList members; Hashtable processed; &lt;span style="color: blue;"&gt;string&lt;/span&gt; attrib; &lt;span style="color: blue;"&gt;public&lt;/span&gt; RecursiveLinkPair(DirectoryEntry
entry, &lt;span style="color: blue;"&gt;string&lt;/span&gt; attrib) { &lt;span style="color: blue;"&gt;if&lt;/span&gt; (entry
== &lt;span style="color: blue;"&gt;null&lt;/span&gt;) &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; ArgumentNullException("entry"); &lt;span style="color: blue;"&gt;if&lt;/span&gt; (String.IsNullOrEmpty(attrib)) &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; ArgumentException("attrib"); &lt;span style="color: blue;"&gt;this&lt;/span&gt;.attrib
= attrib; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.entry = entry; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.processed
= &lt;span style="color: blue;"&gt;new&lt;/span&gt; Hashtable(); &lt;span style="color: blue;"&gt;this&lt;/span&gt;.processed.Add( &lt;span style="color: blue;"&gt;this&lt;/span&gt;.entry.Properties[
"distinguishedName"][0].ToString(), &lt;span style="color: blue;"&gt;null&lt;/span&gt; ); &lt;span style="color: blue;"&gt;this&lt;/span&gt;.members
= Expand(&lt;span style="color: blue;"&gt;this&lt;/span&gt;.entry); } &lt;span style="color: blue;"&gt;public&lt;/span&gt; ArrayList
Members { &lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.members;
} } &lt;span style="color: blue;"&gt;private&lt;/span&gt; ArrayList Expand(DirectoryEntry group)
{ ArrayList al = &lt;span style="color: blue;"&gt;new&lt;/span&gt; ArrayList(5000); DirectorySearcher
ds = &lt;span style="color: blue;"&gt;new&lt;/span&gt; DirectorySearcher( entry, "(objectClass=*)", &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[]
{ &lt;span style="color: blue;"&gt;this&lt;/span&gt;.attrib, "distinguishedName" }, SearchScope.Base
); ds.AttributeScopeQuery = &lt;span style="color: blue;"&gt;this&lt;/span&gt;.attrib; ds.PageSize
= 1000; &lt;span style="color: blue;"&gt;using&lt;/span&gt; (SearchResultCollection src = ds.FindAll())
{ &lt;span style="color: blue;"&gt;string&lt;/span&gt; dn = &lt;span style="color: blue;"&gt;null&lt;/span&gt;; &lt;span style="color: blue;"&gt;foreach&lt;/span&gt; (SearchResult
sr &lt;span style="color: blue;"&gt;in&lt;/span&gt; src) { dn = (&lt;span style="color: blue;"&gt;string&lt;/span&gt;)
sr.Properties["distinguishedName"][0]; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (!&lt;span style="color: blue;"&gt;this&lt;/span&gt;.processed.ContainsKey(dn))
{ &lt;span style="color: blue;"&gt;this&lt;/span&gt;.processed.Add(dn, &lt;span style="color: blue;"&gt;null&lt;/span&gt;);
al.Add(dn); &lt;span style="color: blue;"&gt;if&lt;/span&gt; (sr.Properties.Contains(&lt;span style="color: blue;"&gt;this&lt;/span&gt;.attrib))
{ SetNewPath(&lt;span style="color: blue;"&gt;this&lt;/span&gt;.entry, dn); al.AddRange(Expand(&lt;span style="color: blue;"&gt;this&lt;/span&gt;.entry));
} } } } &lt;span style="color: blue;"&gt;return&lt;/span&gt; al; } &lt;span style="color: green;"&gt;//we
will use IADsPathName utility function instead&lt;/span&gt; &lt;span style="color: green;"&gt;//of
parsing string values. This particular function&lt;/span&gt; &lt;span style="color: green;"&gt;//allows
us to replace only the DN portion of a path&lt;/span&gt; &lt;span style="color: green;"&gt;//and
leave the server and port information intact&lt;/span&gt; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; SetNewPath(DirectoryEntry
entry, &lt;span style="color: blue;"&gt;string&lt;/span&gt; dn) { IAdsPathname pathCracker = (IAdsPathname)&lt;span style="color: blue;"&gt;new&lt;/span&gt; Pathname();
pathCracker.Set(entry.Path, 1); pathCracker.Set(dn, 4); entry.Path = pathCracker.Retrieve(5);
} } [ComImport, Guid("D592AED4-F420-11D0-A36E-00C04FB950DC"), InterfaceType(ComInterfaceType.InterfaceIsDual)] &lt;span style="color: blue;"&gt;internal&lt;/span&gt; &lt;span style="color: blue;"&gt;interface&lt;/span&gt; IAdsPathname
{ [SuppressUnmanagedCodeSecurity] &lt;span style="color: blue;"&gt;int&lt;/span&gt; Set([In, MarshalAs(UnmanagedType.BStr)] &lt;span style="color: blue;"&gt;string&lt;/span&gt; bstrADsPath,
[In, MarshalAs(UnmanagedType.U4)] &lt;span style="color: blue;"&gt;int&lt;/span&gt; lnSetType); &lt;span style="color: blue;"&gt;int&lt;/span&gt; SetDisplayType([In,
MarshalAs(UnmanagedType.U4)] &lt;span style="color: blue;"&gt;int&lt;/span&gt; lnDisplayType);
[&lt;span style="color: blue;"&gt;return&lt;/span&gt;: MarshalAs(UnmanagedType.BStr)] [SuppressUnmanagedCodeSecurity] &lt;span style="color: blue;"&gt;string&lt;/span&gt; Retrieve([In,
MarshalAs(UnmanagedType.U4)] &lt;span style="color: blue;"&gt;int&lt;/span&gt; lnFormatType);
[&lt;span style="color: blue;"&gt;return&lt;/span&gt;: MarshalAs(UnmanagedType.U4)] &lt;span style="color: blue;"&gt;int&lt;/span&gt; GetNumElements();
[&lt;span style="color: blue;"&gt;return&lt;/span&gt;: MarshalAs(UnmanagedType.BStr)] &lt;span style="color: blue;"&gt;string&lt;/span&gt; GetElement([In,
MarshalAs(UnmanagedType.U4)] &lt;span style="color: blue;"&gt;int&lt;/span&gt; lnElementIndex); &lt;span style="color: blue;"&gt;void&lt;/span&gt; AddLeafElement([In,
MarshalAs(UnmanagedType.BStr)] &lt;span style="color: blue;"&gt;string&lt;/span&gt; bstrLeafElement); &lt;span style="color: blue;"&gt;void&lt;/span&gt; RemoveLeafElement();
[&lt;span style="color: blue;"&gt;return&lt;/span&gt;: MarshalAs(UnmanagedType.Interface)] &lt;span style="color: blue;"&gt;object&lt;/span&gt; CopyPath();
[&lt;span style="color: blue;"&gt;return&lt;/span&gt;: MarshalAs(UnmanagedType.BStr)] [SuppressUnmanagedCodeSecurity] &lt;span style="color: blue;"&gt;string&lt;/span&gt; GetEscapedElement([In,
MarshalAs(UnmanagedType.U4)] &lt;span style="color: blue;"&gt;int&lt;/span&gt; lnReserved, [In,
MarshalAs(UnmanagedType.BStr)] &lt;span style="color: blue;"&gt;string&lt;/span&gt; bstrInStr); &lt;span style="color: blue;"&gt;int&lt;/span&gt; EscapedMode
{ &lt;span style="color: blue;"&gt;get&lt;/span&gt;; [SuppressUnmanagedCodeSecurity] &lt;span style="color: blue;"&gt;set&lt;/span&gt;;
} } [ComImport, Guid("080d0d78-f421-11d0-a36e-00c04fb950dc")] &lt;span style="color: blue;"&gt;internal&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; Pathname
{ } &lt;/pre&gt;
&lt;!--EndFragment--&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
Notice I am using the IADsPathName utility interface here.&amp;nbsp; Since recursion requires
us to re-base our search each time, we need to robustly update our DirectoryEntry
instance’s .Path each time.&amp;nbsp; This interface does a much better job than trying
to write your own string parsing routines - especially when you need to preserve server
and port information for things like ADAM.&amp;nbsp; Whenever you see interfaces like
this, check to make sure&amp;nbsp;someone hasn’t already&amp;nbsp;done the setup&amp;nbsp;work
for you.&amp;nbsp; You can check the .NET&amp;nbsp;framework or ActiveDs interop assembly&amp;nbsp;using&amp;nbsp;Reflector
and find the declaration oftentimes.
&lt;/p&gt;
&lt;p&gt;
The final issue we must deal with now is the problem of intermediate values – specifically
how to exclude them.&amp;nbsp; I am going to leave that exercise to the reader with just
a hint:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
I only included&amp;nbsp;2 attributes in each search.&amp;nbsp; If you have already seen my
solution for Group Expansion in the book (Listing 11.6), you will notice that I make
use of a 3rd attribute (objectClass).&amp;nbsp; Did I need to?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Well, this is a long enough post for now.&amp;nbsp; Signing off…
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=d9be43d8-efa0-4680-a894-2d87900434b6" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,d9be43d8-efa0-4680-a894-2d87900434b6.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
      <category>Groups</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=fd8922f9-4e84-48c4-9ca2-a0022bcc4a99</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,fd8922f9-4e84-48c4-9ca2-a0022bcc4a99.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,fd8922f9-4e84-48c4-9ca2-a0022bcc4a99.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=fd8922f9-4e84-48c4-9ca2-a0022bcc4a99</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
With very little fanfare, I am announcing that the companion site for ‘<a href="http://www.amazon.com/gp/product/0321350170/ref=ase_extemporaneou-20">The
.NET Developer’s Guide to Directory Services Programming</a>’ is available now. 
We have managed to snag a fairly relevant domain name for it and rushed to put out
a <a href="http://communityserver.org/">Community Server</a> based site (a review
on this tool later perhaps).  You can find it here:
</p>
        <p>
          <a href="http://directoryprogramming.net/">Directory Programming .NET</a>
          <a href="http://directoryprogramming.net/">
          </a>
        </p>
        <p>
Our first order of business is to get the code samples out there.  Right now,
we have released what I term the ‘raw’ samples as they are verbatim from the book
(<a href="http://directoryprogramming.net/files/default.aspx">available here</a>). 
The samples are still a great start even though they are slightly truncated in some
cases.  The truncation will only affect the more sophisticated examples we have
in the book that would have taken pages of code to print in entirety.
</p>
        <p>
My next order of business is to finish converting all the book samples into a more
easy to consume test harness release.  I say ‘test-harness’ in a loose manner
as TDD guys will probably not be satisfied.  I have put together ad-hoc test
cases for each of the non-trivial samples in the book and modified them to work with
configuration (so you don’t have to hardcode your domain over and over again, for
instance).  This is taking some time, but should be done shortly.  Once
this is done, you can use <a href="http://testdriven.net/">TestDriven.NET</a> or <a href="http://nunit.org/">NUnit </a>to
run these guys pretty easily.
</p>
        <p>
Future plans for the site include more and more samples (not from the book necessarily)
as well as a place for us to publish errata and updates as we find them.  We
have enabled the forums feature as of now and will gauge its usefulness as we go.
</p>
        <p>
My co-author Joe is on the hook to convert all the samples to VB.NET.  I don’t
particularly envy him – we didn’t realize how many frickin samples we had until we
tried to put them all together.  He has his work cut out for him.
</p>
        <p>
As for when you can get your hands on a copy of the book.  The answer is… now. 
It is in stock at <a href="http://www.awprofessional.com/title/0321350170">Addison-Wesley</a> and
Amazon and other retailers should have it stocked any time now.  Brick and mortar
stores will be last, but should be in the next week or so.  Of course, purchasing
it through <a href="http://www.amazon.com/gp/product/0321350170/ref=ase_extemporaneou-20">my
Amazon link</a> on this site or the companion site would be appreciated since we are
running this companion site out of our own pockets.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=fd8922f9-4e84-48c4-9ca2-a0022bcc4a99" />
      </body>
      <title>DotNetDevGuide to Directory Services Companion Site Launched</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,fd8922f9-4e84-48c4-9ca2-a0022bcc4a99.aspx</guid>
      <link>http://dunnry.com/blog/2006/05/11/DotNetDevGuideToDirectoryServicesCompanionSiteLaunched.aspx</link>
      <pubDate>Thu, 11 May 2006 17:22:57 GMT</pubDate>
      <description>&lt;p&gt;
With very little fanfare, I am announcing that the companion site for ‘&lt;a href="http://www.amazon.com/gp/product/0321350170/ref=ase_extemporaneou-20"&gt;The
.NET Developer’s Guide to Directory Services Programming&lt;/a&gt;’ is available now.&amp;nbsp;
We have managed to snag a fairly relevant domain name for it and rushed to put out
a &lt;a href="http://communityserver.org/"&gt;Community Server&lt;/a&gt; based site (a review
on this tool later perhaps).&amp;nbsp; You can find it here:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://directoryprogramming.net/"&gt;Directory Programming .NET&lt;/a&gt;&lt;a href="http://directoryprogramming.net/"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Our first order of business is to get the code samples out there.&amp;nbsp; Right now,
we have released what I term the ‘raw’ samples as they are verbatim from the book
(&lt;a href="http://directoryprogramming.net/files/default.aspx"&gt;available here&lt;/a&gt;).&amp;nbsp;
The samples are still a great start even though they are slightly truncated in some
cases.&amp;nbsp; The truncation will only affect the more sophisticated examples we have
in the book that would have taken pages of code to print in entirety.
&lt;/p&gt;
&lt;p&gt;
My next order of business is to finish converting all the book samples into a more
easy to consume test harness release.&amp;nbsp; I say ‘test-harness’ in a loose manner
as TDD guys will probably not be satisfied.&amp;nbsp; I have put together ad-hoc test
cases for each of the non-trivial samples in the book and modified them to work with
configuration (so you don’t have to hardcode your domain over and over again, for
instance).&amp;nbsp; This is taking some time, but should be done shortly.&amp;nbsp; Once
this is done, you can use &lt;a href="http://testdriven.net/"&gt;TestDriven.NET&lt;/a&gt; or &lt;a href="http://nunit.org/"&gt;NUnit &lt;/a&gt;to
run these guys pretty easily.
&lt;/p&gt;
&lt;p&gt;
Future plans for the site include more and more samples (not from the book necessarily)
as well as a place for us to publish errata and updates as we find them.&amp;nbsp; We
have enabled the forums feature as of now and will gauge its usefulness as we go.
&lt;/p&gt;
&lt;p&gt;
My co-author Joe is on the hook to convert all the samples to VB.NET.&amp;nbsp; I don’t
particularly envy him – we didn’t realize how many frickin samples we had until we
tried to put them all together.&amp;nbsp; He has his work cut out for him.
&lt;/p&gt;
&lt;p&gt;
As for when you can get your hands on a copy of the book.&amp;nbsp; The answer is… now.&amp;nbsp;
It is in stock at &lt;a href="http://www.awprofessional.com/title/0321350170"&gt;Addison-Wesley&lt;/a&gt; and
Amazon and other retailers should have it stocked any time now.&amp;nbsp; Brick and mortar
stores will be last, but should be in the next week or so.&amp;nbsp; Of course, purchasing
it through &lt;a href="http://www.amazon.com/gp/product/0321350170/ref=ase_extemporaneou-20"&gt;my
Amazon link&lt;/a&gt; on this site or the companion site would be appreciated since we are
running this companion site out of our own pockets.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=fd8922f9-4e84-48c4-9ca2-a0022bcc4a99" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,fd8922f9-4e84-48c4-9ca2-a0022bcc4a99.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
      <category>Book</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=2275e539-a273-4c6f-996d-5b2fe46be676</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,2275e539-a273-4c6f-996d-5b2fe46be676.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,2275e539-a273-4c6f-996d-5b2fe46be676.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=2275e539-a273-4c6f-996d-5b2fe46be676</wfw:commentRss>
      <title>Self Service Updates in Active Directory</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,2275e539-a273-4c6f-996d-5b2fe46be676.aspx</guid>
      <link>http://dunnry.com/blog/2006/05/05/SelfServiceUpdatesInActiveDirectory.aspx</link>
      <pubDate>Fri, 05 May 2006 14:43:21 GMT</pubDate>
      <description>&lt;p&gt;
Sometimes AD Administrators would like to allow end users to update and maintain their
own information in the directory.&amp;nbsp; Of course, this is not without risk &amp;ndash;
more adventurous users will change their title to &amp;ldquo;Chief Code Monkey&amp;rdquo;
or something perhaps even less professional.&amp;nbsp; I was an &amp;lsquo;Executive Vice-President&amp;rsquo;
myself for some period of time and it made for some interesting phone conversations
with co-workers that did not know me personally (it turns out people are pretty fearful
of talking directly to EVPs).
&lt;/p&gt;
&lt;p&gt;
However, by default, users have permission over a property set in the schema that
allows them to update attributes on their own user object.&amp;nbsp; If these permissions
have not been updated from the default, the user will generally have free reign to
update their own personal information.&amp;nbsp; Which attributes, you ask?&amp;nbsp; Earlier
I demonstrated &lt;a href="http://dunnry.com/blog/WhatAttributesAreAvailableOnMyActiveDirectoryObject.aspx"&gt;a
way to determine what attributes are available&lt;/a&gt; on a given class.&amp;nbsp; This involved
finding the object&amp;nbsp;we wanted in the directory and programmatically inspecting
the schema.&amp;nbsp; It turns out there is another way to achieve the same thing, and
with a twist &amp;ndash; allow us to see which attributes we can update ourselves.
&lt;/p&gt;
&lt;p&gt;
Active Directory (and ADAM) contain a couple attributes called &amp;lsquo;allowedAttributes&amp;rsquo;
and &amp;lsquo;allowedAttributesEffective&amp;rsquo; that tell us all of the attributes on
a given object and all of the attributes on a given object that we are allowed to
update, respectively.&amp;nbsp; The first one, &amp;lsquo;allowedAttributes&amp;rsquo; produces
the exact output as inspecting the OptionalProperties and MandatoryProperties together
(without distinction, however).&amp;nbsp; It gets more interesting with the second one,
because it opens the possibility that we can easily generate a dynamic UI to allow
the user to update any attributes where their permission allows.
&lt;/p&gt;
&lt;p&gt;
Here is one such example:
&lt;/p&gt;
&lt;div style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: black; FONT-FAMILY: Courier New"&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="BACKGROUND: yellow"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="COLOR: blue"&gt;@&lt;/span&gt; &lt;span style="COLOR: maroon"&gt;Assembly&lt;/span&gt; &lt;span style="COLOR: red"&gt;Name&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="System.DirectoryServices,
Version=2.0.0000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"&lt;/span&gt; &lt;span style="BACKGROUND: yellow"&gt;%&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="BACKGROUND: yellow"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="COLOR: blue"&gt;@&lt;/span&gt; &lt;span style="COLOR: maroon"&gt;Import&lt;/span&gt; &lt;span style="COLOR: red"&gt;Namespace&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="System.DirectoryServices"&lt;/span&gt; &lt;span style="BACKGROUND: yellow"&gt;%&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="BACKGROUND: yellow"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="COLOR: blue"&gt;@&lt;/span&gt; &lt;span style="COLOR: maroon"&gt;Import&lt;/span&gt; &lt;span style="COLOR: red"&gt;Namespace&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="System.Text"&lt;/span&gt; &lt;span style="BACKGROUND: yellow"&gt;%&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;html&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;head&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;script&lt;/span&gt; &lt;span style="COLOR: red"&gt;language&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="c#"&lt;/span&gt; &lt;span style="COLOR: red"&gt;runat&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="server"&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;static&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; adsPath
= &lt;span style="COLOR: maroon"&gt;"LDAP://dc=yourdomain,dc=com"&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; Page_Load(&lt;span style="COLOR: blue"&gt;object&lt;/span&gt; sender,
System.&lt;span style="COLOR: teal"&gt;EventArgs&lt;/span&gt; e)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (!Page.IsPostBack)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;SearchResult&lt;/span&gt; sr
= FindCurrentUser(&lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt;[]
{ &lt;span style="COLOR: maroon"&gt;"allowedAttributesEffective"&lt;/span&gt; });
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (sr
== &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
msg.Text = &lt;span style="COLOR: maroon"&gt;"User not found..."&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; count
= sr.Properties[&lt;span style="COLOR: maroon"&gt;"allowedAttributesEffective"&lt;/span&gt;].Count;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (count
&amp;gt; 0)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;int&lt;/span&gt; i
= 0;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt;[]
effectiveAttributes = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt;[count];
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;string&lt;/span&gt; attrib &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; sr.Properties[&lt;span style="COLOR: maroon"&gt;"allowedAttributesEffective"&lt;/span&gt;])
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; effectiveAttributes[i++] = attrib;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
}
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
sr = FindCurrentUser(effectiveAttributes);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;string&lt;/span&gt; key &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; effectiveAttributes)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; val = &lt;span style="COLOR: teal"&gt;String&lt;/span&gt;.Empty;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (sr.Properties.Contains(key))
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; val = sr.Properties[key][0].ToString();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; GenerateControls(key, val, parent);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
}
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;else&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; UpdateControls();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: teal"&gt;SearchResult&lt;/span&gt; FindCurrentUser(&lt;span style="COLOR: blue"&gt;string&lt;/span&gt;[]
attribsToLoad)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//parse
the current user's logon name as search key&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; sFilter
= &lt;span style="COLOR: teal"&gt;String&lt;/span&gt;.Format(
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: maroon"&gt;"(&amp;amp;(objectClass=user)(objectCategory=person)(sAMAccountName={0}))"&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; User.Identity.Name.Split(&lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: blue"&gt;char&lt;/span&gt;[]
{ &lt;span style="COLOR: maroon"&gt;'\\'&lt;/span&gt; })[1]
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; );
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;DirectoryEntry&lt;/span&gt; searchRoot
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;DirectoryEntry&lt;/span&gt;(
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; adsPath,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;AuthenticationTypes&lt;/span&gt;.Secure
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; );
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;using&lt;/span&gt; (searchRoot)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;DirectorySearcher&lt;/span&gt; ds
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;DirectorySearcher&lt;/span&gt;(
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
searchRoot,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
sFilter,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
attribsToLoad,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;SearchScope&lt;/span&gt;.Subtree
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ds.SizeLimit
= 1;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; ds.FindOne();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; GenerateControls(&lt;span style="COLOR: blue"&gt;string&lt;/span&gt; attrib, &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; val, &lt;span style="COLOR: teal"&gt;Control&lt;/span&gt; parent)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; parent.Controls.Add(&lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;LiteralControl&lt;/span&gt;(&lt;span style="COLOR: maroon"&gt;"&amp;lt;div&amp;gt;"&lt;/span&gt;));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;TextBox&lt;/span&gt; t
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;TextBox&lt;/span&gt;();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; t.ID = &lt;span style="COLOR: maroon"&gt;"c_"&lt;/span&gt; +
attrib;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; t.Text = val;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; t.CssClass = &lt;span style="COLOR: maroon"&gt;"txt"&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;Label&lt;/span&gt; l
= &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;Label&lt;/span&gt;();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; l.Text = attrib;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; l.AssociatedControlID = t.ID;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; l.CssClass = &lt;span style="COLOR: maroon"&gt;"lbl"&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; parent.Controls.Add(l);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; parent.Controls.Add(t);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; parent.Controls.Add(&lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: teal"&gt;LiteralControl&lt;/span&gt;(&lt;span style="COLOR: maroon"&gt;"&amp;lt;/div&amp;gt;"&lt;/span&gt;));
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; UpdateControls()
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: teal"&gt;SearchResult&lt;/span&gt; sr
= FindCurrentUser(&lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt;[]
{ &lt;span style="COLOR: maroon"&gt;"cn"&lt;/span&gt; });
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (sr
!= &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;using&lt;/span&gt; (&lt;span style="COLOR: teal"&gt;DirectoryEntry&lt;/span&gt; user
= sr.GetDirectoryEntry())
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;string&lt;/span&gt; key &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; Request.Form.AllKeys)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (key.StartsWith(&lt;span style="COLOR: maroon"&gt;"c_"&lt;/span&gt;))
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; attrib
= key.Split(&lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: blue"&gt;char&lt;/span&gt;[]
{ &lt;span style="COLOR: maroon"&gt;'_'&lt;/span&gt; })[1];
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; val
= Request.Form[key];
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (!&lt;span style="COLOR: teal"&gt;String&lt;/span&gt;.IsNullOrEmpty(val))
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Response.Output.Write(&lt;span style="COLOR: maroon"&gt;"Updating
{0} to {1}&amp;lt;br&amp;gt;"&lt;/span&gt;, attrib, val);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; user.Properties[attrib].Value
= val;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
}
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
user.CommitChanges();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; btnSubmit.Visible = &lt;span style="COLOR: blue"&gt;false&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Response.Output.Write(&lt;span style="COLOR: maroon"&gt;"&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;a
href=\"{0}\"&amp;gt;&amp;amp;lt;&amp;amp;nbsp;Back&amp;lt;/a&amp;gt;"&lt;/span&gt;, Request.Url);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;script&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;style&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: maroon"&gt;.lbl&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: red"&gt;margin-left&lt;/span&gt;: &lt;span style="COLOR: blue"&gt;25px&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: red"&gt;clear&lt;/span&gt;: &lt;span style="COLOR: blue"&gt;left&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: red"&gt;width&lt;/span&gt;: &lt;span style="COLOR: blue"&gt;250px&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: maroon"&gt;.txt&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: red"&gt;width&lt;/span&gt;: &lt;span style="COLOR: blue"&gt;250px&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;style&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;head&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;body&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;form&lt;/span&gt; &lt;span style="COLOR: red"&gt;id&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="main"&lt;/span&gt; &lt;span style="COLOR: red"&gt;runat&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="server"&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Data for user:
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="BACKGROUND: yellow"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;User.Identity.Name&lt;span style="BACKGROUND: yellow"&gt;%&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;br&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;br&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;asp&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;Label&lt;/span&gt; &lt;span style="COLOR: red"&gt;ID&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="msg"&lt;/span&gt; &lt;span style="COLOR: red"&gt;runat&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="server"&lt;/span&gt; &lt;span style="COLOR: blue"&gt;/&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;asp&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;Panel&lt;/span&gt; &lt;span style="COLOR: red"&gt;ID&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="parent"&lt;/span&gt; &lt;span style="COLOR: red"&gt;runat&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="server"&lt;/span&gt; &lt;span style="COLOR: blue"&gt;/&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;asp&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;Button&lt;/span&gt; &lt;span style="COLOR: red"&gt;ID&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="btnSubmit"&lt;/span&gt; &lt;span style="COLOR: red"&gt;runat&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="server"&lt;/span&gt; &lt;span style="COLOR: red"&gt;Text&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="Update"&lt;/span&gt; &lt;span style="COLOR: blue"&gt;/&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;form&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;body&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: maroon"&gt;html&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
Pretty easy, eh?&amp;nbsp; Sure, this one was whacked together in about 20 minutes, but
you could create something similar that takes care of the single- vs. multi-value
attribute treatment and make it a whole lot prettier with a little more effort.
&lt;/p&gt;
&lt;p&gt;
This should be fairly obvious &amp;ndash; but it bears mentioning:&amp;nbsp; This requires
you to use Integrated Windows Authentication with impersonation and your IIS server
must be set for delegation.&amp;nbsp; The whole point of this exercise was to allow the
user to update their own information using their own credentials.&amp;nbsp; Using a service
account will show you what attributes &lt;em&gt;the service account&lt;/em&gt; has permission
to update on the object.
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;(thanks Paul for the css &amp;ndash; yeah, I am teh suck on UI)&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=2275e539-a273-4c6f-996d-5b2fe46be676" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,2275e539-a273-4c6f-996d-5b2fe46be676.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
      <category>ASP.NET</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=3d9ba5cd-fcf8-4163-89ae-67371d765d18</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,3d9ba5cd-fcf8-4163-89ae-67371d765d18.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,3d9ba5cd-fcf8-4163-89ae-67371d765d18.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=3d9ba5cd-fcf8-4163-89ae-67371d765d18</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
A little old, but I found <a href="http://msdn.microsoft.com/library/en-us/dntablet/html/tbconSudokuSampleFinal.asp?frame=true">this
article</a> on MSDN.  What a sweet looking application for the Tablet PC. 
Anything Steven Toub writes seems to be pure gold (check out his <a href="http://msdn.microsoft.com/library/en-us/dnxpmce/html/dvr-ms.asp?frame=true">Fun
with DVR-MS</a> article as well).  It makes me want to get one just to try it. 
I have only played Suduko a couple times on the plane when I found a puzzle in the
in-flight magazines.  I was surprised at how addictive it was – it kept me entertained
the almost the whole trip (yeah, I was slow the first time).
</p>
        <p>
 
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=3d9ba5cd-fcf8-4163-89ae-67371d765d18" />
      </body>
      <title>Suduko for Tablet PC</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,3d9ba5cd-fcf8-4163-89ae-67371d765d18.aspx</guid>
      <link>http://dunnry.com/blog/2006/04/26/SudukoForTabletPC.aspx</link>
      <pubDate>Wed, 26 Apr 2006 14:35:22 GMT</pubDate>
      <description>&lt;p&gt;
A little old, but I found &lt;a href="http://msdn.microsoft.com/library/en-us/dntablet/html/tbconSudokuSampleFinal.asp?frame=true"&gt;this
article&lt;/a&gt; on MSDN.&amp;nbsp; What a sweet looking application for the Tablet PC.&amp;nbsp;
Anything Steven Toub writes seems to be pure gold (check out his &lt;a href="http://msdn.microsoft.com/library/en-us/dnxpmce/html/dvr-ms.asp?frame=true"&gt;Fun
with DVR-MS&lt;/a&gt; article as well).&amp;nbsp; It makes me want to get one just to try it.&amp;nbsp;
I have only played Suduko a couple times on the plane when I found a puzzle in the
in-flight magazines.&amp;nbsp; I was surprised at how addictive it was – it kept me entertained
the almost the whole trip (yeah, I was slow the first time).
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=3d9ba5cd-fcf8-4163-89ae-67371d765d18" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,3d9ba5cd-fcf8-4163-89ae-67371d765d18.aspx</comments>
      <category>.NET</category>
      <category>Games</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=6a3d6efa-0641-4d84-a24e-72057632f678</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,6a3d6efa-0641-4d84-a24e-72057632f678.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,6a3d6efa-0641-4d84-a24e-72057632f678.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=6a3d6efa-0641-4d84-a24e-72057632f678</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Scott Guthrie <a href="http://weblogs.asp.net/scottgu/archive/2006/04/20/443513.aspx">has
some good news</a> for the ADSI folks that have struggled so much with the IIS provider
until now.  These new, <a href="http://blogs.msdn.com/carlosag/archive/2006/04/17/MicrosoftWebAdministration.aspx">managed
APIs </a>for IIS should replace all the spackle that was crusted onto ADSI to wedge
the IIS provider into that model.  Granted, this is not really available yet
- but at least relief it in sight.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=6a3d6efa-0641-4d84-a24e-72057632f678" />
      </body>
      <title>The next IIS provider</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,6a3d6efa-0641-4d84-a24e-72057632f678.aspx</guid>
      <link>http://dunnry.com/blog/2006/04/24/TheNextIISProvider.aspx</link>
      <pubDate>Mon, 24 Apr 2006 22:36:11 GMT</pubDate>
      <description>&lt;p&gt;
Scott Guthrie &lt;a href="http://weblogs.asp.net/scottgu/archive/2006/04/20/443513.aspx"&gt;has
some good news&lt;/a&gt; for the ADSI folks that have struggled so much with the IIS provider
until now.&amp;nbsp; These new, &lt;a href="http://blogs.msdn.com/carlosag/archive/2006/04/17/MicrosoftWebAdministration.aspx"&gt;managed
APIs &lt;/a&gt;for IIS should replace all the spackle that was crusted onto ADSI to wedge
the IIS provider into that model.&amp;nbsp; Granted, this is not really available yet
- but at least relief it in sight.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=6a3d6efa-0641-4d84-a24e-72057632f678" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,6a3d6efa-0641-4d84-a24e-72057632f678.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>ASP.NET</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=141635c9-953d-4c6a-a938-051157d2cff2</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,141635c9-953d-4c6a-a938-051157d2cff2.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,141635c9-953d-4c6a-a938-051157d2cff2.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=141635c9-953d-4c6a-a938-051157d2cff2</wfw:commentRss>
      <title>What a small world</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,141635c9-953d-4c6a-a938-051157d2cff2.aspx</guid>
      <link>http://dunnry.com/blog/2006/04/07/WhatASmallWorld.aspx</link>
      <pubDate>Fri, 07 Apr 2006 15:25:21 GMT</pubDate>
      <description>&lt;p&gt;
I was reading&amp;nbsp;&lt;a href="http://dotavery.com/blog/archive/2006/04/06/10118.aspx"&gt;a
post&lt;/a&gt; by my friend (and ex-coworker) James Avery today that made me want to checkout
the status of the &lt;a href="http://www.nhibernate.org/"&gt;NHibernate&lt;/a&gt; project.&amp;nbsp;
I had heard of this project a long time ago, but never looked into at all.&amp;nbsp; So,
browsing the first page I see a name I am pretty sure I recognize &amp;ndash; Mike Doerfler.&amp;nbsp;
He is listed as one of the main contributors to the project on the homepage.
&lt;/p&gt;
&lt;p&gt;
The funny part is that Mike and I used to teach classic ASP together back in the day
when we both worked at Ernst &amp;amp; Young.&amp;nbsp; I think the market had slowed or something
and we needed to keep busy, so we took the job as an internal project to teach the
basics of ASP programming.&amp;nbsp; I can still remember how easy it was to crash the
NT4 servers when students either put their database or UI code into infinite loops.&amp;nbsp;
Having 20 generally horrible developers work on a single IIS server and one database
server is like locking a couple&amp;nbsp;sheep into the same room with a bunch of wolves...
the poor things never stood a chance.
&lt;/p&gt;
&lt;p&gt;
So, I am pretty sure Mike left in 1999 or 2000 and we slowly lost touch.&amp;nbsp; I have
a ton of MSN Messenger contacts and Mike has been on there forever though the chats
have been fewer and fewer until non-existent.&amp;nbsp; To be fair, I almost never chat
with anyone anymore.&amp;nbsp; First, I am hardly ever online with Messenger, and second,
I just don&amp;rsquo;t have a lot to chat about.
&lt;/p&gt;
&lt;p&gt;
Anyhow, I had to send Mike an IM to see if it was the same &amp;lsquo;Doerfler&amp;rsquo;.&amp;nbsp;
Turns out it was!&amp;nbsp; Now, I wonder who else is on my IM list that has gone on to
fame and fortune&amp;hellip;&amp;nbsp; I really need to do a better job of keeping in touch
with people.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=141635c9-953d-4c6a-a938-051157d2cff2" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,141635c9-953d-4c6a-a938-051157d2cff2.aspx</comments>
      <category>.NET</category>
      <category>Personal</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=a4c609a2-546a-44c8-9661-94173b649bef</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,a4c609a2-546a-44c8-9661-94173b649bef.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,a4c609a2-546a-44c8-9661-94173b649bef.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=a4c609a2-546a-44c8-9661-94173b649bef</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Joe and I had a great time on Wednesday presenting our talk on Directory Services
Programming in .NET.  Being the first time that we have ever presented together,
we did no know exactly how it would work out.  All in all, we felt it went pretty
well.  Thanks to everyone that attended!
</p>
        <p>
One of the cool parts for us was that our publisher sent over some draft copies of
the book.  We knew our publisher was sending something, but we had thought it
was a sample chapter or two.  It was quite surprising to open the box and find
the full text!  Seeing your hard work in print for the first time almost gives
you goose bumps.
</p>
        <p>
As promised, I am attaching <a title="presentation material" href="http://dunnry.com/blog/content/binary/dec2006.zip">the
presentation material</a> to this post.  It includes the updated presentation
that we used as well as all the samples that we used during it.  We actually
did not get to one of the samples called Dirsync, which allows us to poll the directory
periodically for updates, so check it out.
</p>
        <p>
If anyone has questions on these samples or the topic itself, Joe and I can be reached
through the MS newsgroups or the <a href="http://forums.asp.net/93/ShowForum.aspx">ASP.NET
Forums</a>.  I would also suggest checking out what I consider <a href="http://dunnry.com/blog/UsefulSystemDirectoryServicesResources.aspx">useful
System.DirectoryServices resources</a>.  I will try to keep that updated as I
find more.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=a4c609a2-546a-44c8-9661-94173b649bef" />
      </body>
      <title>DEC 2006 Wrap Up and Presentation Material</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,a4c609a2-546a-44c8-9661-94173b649bef.aspx</guid>
      <link>http://dunnry.com/blog/2006/03/31/DEC2006WrapUpAndPresentationMaterial.aspx</link>
      <pubDate>Fri, 31 Mar 2006 18:32:48 GMT</pubDate>
      <description>&lt;p&gt;
Joe and I had&amp;nbsp;a great time on Wednesday presenting our talk on Directory Services
Programming in .NET.&amp;nbsp; Being the first time that we have ever presented together,
we did no know exactly how it would work out.&amp;nbsp; All in all, we felt it went pretty
well.&amp;nbsp; Thanks to everyone that attended!
&lt;/p&gt;
&lt;p&gt;
One of the cool parts for us was that our publisher sent over some draft copies of
the book.&amp;nbsp; We knew our publisher was sending something, but we had thought it
was a sample chapter or two.&amp;nbsp; It was quite surprising to open the box and find
the full text!&amp;nbsp; Seeing your hard work in print for the first time almost gives
you goose bumps.
&lt;/p&gt;
&lt;p&gt;
As promised, I am attaching &lt;a title="presentation material" href="http://dunnry.com/blog/content/binary/dec2006.zip"&gt;the
presentation material&lt;/a&gt; to this post.&amp;nbsp; It includes the updated presentation
that we used as well as all the samples that we used during it.&amp;nbsp; We actually
did not get to one of the samples called Dirsync, which allows us to poll the directory
periodically for updates, so check it out.
&lt;/p&gt;
&lt;p&gt;
If anyone has questions on these samples or the topic itself, Joe and I can be reached
through the MS newsgroups or the &lt;a href="http://forums.asp.net/93/ShowForum.aspx"&gt;ASP.NET
Forums&lt;/a&gt;.&amp;nbsp; I would also suggest checking out what I consider &lt;a href="http://dunnry.com/blog/UsefulSystemDirectoryServicesResources.aspx"&gt;useful
System.DirectoryServices resources&lt;/a&gt;.&amp;nbsp; I will try to keep that updated as I
find more.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=a4c609a2-546a-44c8-9661-94173b649bef" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,a4c609a2-546a-44c8-9661-94173b649bef.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
      <category>Tips</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=32652994-4249-4ad1-9401-d243add887ec</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,32652994-4249-4ad1-9401-d243add887ec.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,32652994-4249-4ad1-9401-d243add887ec.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=32652994-4249-4ad1-9401-d243add887ec</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I had a great time in Las Vegas this last week at the DEC 2006 conference.  It
was great connecting with so many of the participants as well as the personalities
involved in the presentations.  There were some really good presentations that
I attended (e.g. Guido, Dean &amp; Joe, and Stuart’s), and getting to speak one-on-one
with so many of the product manager’s of the involved technologies was great. 
The conference was big, but not TechEd big, so the interactions were of much better
quality in my opinion.
</p>
        <p>
I was surprised to run into only a couple people from Avanade there, however. 
Being a large Microsoft consulting company, I would have thought we would have more
folks from our infrastructure practice there learning, if not speaking themselves.
</p>
        <p>
The last day of the conference was fun.  We had a nice dinner with a bunch of
folks – Katherine Coombs, Joe Richards, Dean Wells, Paul Williams, Don Wells (Dean’s
dad), and Eric.  Listening to the different accents and slang (Dutch, Welsh,
English, and Aussie/English mix) was a trip.  On a side note – if Paul Williams
is any indicator – Welshmen eat entire cakes for dinner and prefer their cow-flesh
raw.  When asked, “what temperature” he would like his burger cooked, Paul looked
around quizzically and said, “warm?”.  This was after, of course, he had devoured
a 10 lb. brownie (not joking here) for lunch – we are talking a dense pile of chocolate
that could cause serious injury if dropped on a man’s foot.
</p>
        <p>
I did not have a hotel room for the last night before my 7am flight back to Cleveland. 
Initially, I had planned to stay up the night and just go to the airport nice and
early.  However, after Gil, Katherine, Dean, Jorge, Paul, and Ulf decided one
after another to go to bed, I would have been left alone with the hardcore gamblers/insomniacs/general
freaks in Vegas at that hour.  Ulf was kind enough to let me have his extra bed
for 3 invigorating hours of sleep before departing for the airport.
</p>
        <p>
If Gil would have me back next year, I would definitely do it again.
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=32652994-4249-4ad1-9401-d243add887ec" />
      </body>
      <title>DEC 2006 thoughts</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,32652994-4249-4ad1-9401-d243add887ec.aspx</guid>
      <link>http://dunnry.com/blog/2006/03/31/DEC2006Thoughts.aspx</link>
      <pubDate>Fri, 31 Mar 2006 18:24:55 GMT</pubDate>
      <description>&lt;p&gt;
I had a great time in Las Vegas this last week at the DEC 2006 conference.&amp;nbsp; It
was great connecting with so many of the participants as well as the personalities
involved in the presentations.&amp;nbsp; There were some really good presentations that
I attended (e.g. Guido, Dean &amp;amp; Joe, and Stuart’s), and getting to speak one-on-one
with so many of the product manager’s of the involved technologies was great.&amp;nbsp;
The conference was big, but not TechEd big, so the interactions were of much better
quality in my opinion.
&lt;/p&gt;
&lt;p&gt;
I was surprised to run into only a couple people from Avanade there, however.&amp;nbsp;
Being a large Microsoft consulting company, I would have thought we would have more
folks from our infrastructure practice there learning, if not speaking themselves.
&lt;/p&gt;
&lt;p&gt;
The last day of the conference was fun.&amp;nbsp; We had a nice dinner with a bunch of
folks – Katherine Coombs, Joe Richards, Dean Wells, Paul Williams, Don Wells (Dean’s
dad), and Eric.&amp;nbsp; Listening to the different accents and slang (Dutch, Welsh,
English, and Aussie/English mix) was a trip.&amp;nbsp; On a side note – if Paul Williams
is any indicator – Welshmen eat entire cakes for dinner and prefer their cow-flesh
raw.&amp;nbsp; When asked, “what temperature” he would like his burger cooked, Paul looked
around quizzically and said, “warm?”.&amp;nbsp; This was after, of course, he had devoured
a 10 lb. brownie (not joking here) for lunch – we are talking a dense pile of chocolate
that could cause serious injury if dropped on a man’s foot.
&lt;/p&gt;
&lt;p&gt;
I did not have a hotel room for the last night before my 7am flight back to Cleveland.&amp;nbsp;
Initially, I had planned to stay up the night and just go to the airport nice and
early.&amp;nbsp; However, after Gil, Katherine, Dean, Jorge, Paul, and Ulf decided one
after another to go to bed, I would have been left alone with the hardcore gamblers/insomniacs/general
freaks in Vegas at that hour.&amp;nbsp; Ulf was kind enough to let me have his extra bed
for 3 invigorating hours of sleep before departing for the airport.
&lt;/p&gt;
&lt;p&gt;
If Gil would have me back next year, I would definitely do it again.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=32652994-4249-4ad1-9401-d243add887ec" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,32652994-4249-4ad1-9401-d243add887ec.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=1707c3e7-5395-45f4-8882-3a17f291934b</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,1707c3e7-5395-45f4-8882-3a17f291934b.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,1707c3e7-5395-45f4-8882-3a17f291934b.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=1707c3e7-5395-45f4-8882-3a17f291934b</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
One of the new features of .NET 2.0 is the System.DirectoryServices.Protocols (SDS.P)
namespace that gives us access to the native LDAP api without relying on ADSI. 
We can accomplish pretty much anything now in LDAP using managed code and we get around
some of the wonkiness of ADSI.
</p>
        <p>
Performing a simple search in SDS.P is pretty straightforward actually.  We just
create a connection to the directory using the LdapConnection class, bind to the connection
and then make request/response pairs on the connection.  One of the request/response
pairs is SearchRequest and SearchResponse.  Without going into too many details,
using these two classes in a synchronous manner is pretty easy.  What might be
surprising however is that developers will often run into the following error:
</p>
        <p>
          <font face="Courier New" size="2">System.DirectoryServices.Protocols.DirectoryOperationException
: The size limit was exceeded</font>
        </p>
        <p>
This departs from System.DirectoryServices (SDS) and ADSI where we do not get errors
for simple searches even if we have not enabled paging.  In SDS, a similar query
with DirectorySearcher would just return the MaxPageSize for the directory (usually
1000).  We know from SDS that to get more than the MaxPageSize, we need to use
paging.  That is as simple as setting DirectorySearcher.PageSize &gt; 0.
</p>
        <p>
So, what about SDS.P.  It turns out that one of the really nice things that ADSI
did for us was make paging so seamless.  If we wanted to use it, we simply asked
for a specific page size and it just worked.  Now, since we are at a lower level,
we need to take care of these details ourselves (native LDAP programmers already know
this of course).
</p>
        <p>
How do we do this in SDS.P?  Here is some sample code that implements paging
and returns a collection of SearchResultEntry objects.
</p>
        <div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 8pt; BACKGROUND: white; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: black; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Lucida Console">
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">private</span> List<span style="FONT-WEIGHT: bold; COLOR: maroon">&lt;</span>SearchResultEntry<span style="FONT-WEIGHT: bold; COLOR: maroon">&gt;</span> PerformPagedSearch(
</p>
          <p style="MARGIN: 0px">
    LdapConnection connection,
</p>
          <p style="MARGIN: 0px">
    <span style="COLOR: blue">string</span> baseDN,
</p>
          <p style="MARGIN: 0px">
    <span style="COLOR: blue">string</span> filter,
</p>
          <p style="MARGIN: 0px">
    <span style="COLOR: blue">string</span>[] attribs)
</p>
          <p style="MARGIN: 0px">
{
</p>
          <p style="MARGIN: 0px">
    List<span style="FONT-WEIGHT: bold; COLOR: maroon">&lt;</span>SearchResultEntry<span style="FONT-WEIGHT: bold; COLOR: maroon">&gt;</span> results <span style="FONT-WEIGHT: bold; COLOR: maroon">=</span><span style="COLOR: blue">new</span> List<span style="FONT-WEIGHT: bold; COLOR: maroon">&lt;</span>SearchResultEntry<span style="FONT-WEIGHT: bold; COLOR: maroon">&gt;</span>();
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
        SearchRequest request <span style="FONT-WEIGHT: bold; COLOR: maroon">=</span><span style="COLOR: blue">new</span> SearchRequest(
</p>
          <p style="MARGIN: 0px">
            baseDN,
</p>
          <p style="MARGIN: 0px">
            filter,
</p>
          <p style="MARGIN: 0px">
            System<span style="FONT-WEIGHT: bold; COLOR: maroon">.</span>DirectoryServices<span style="FONT-WEIGHT: bold; COLOR: maroon">.</span>Protocols<span style="FONT-WEIGHT: bold; COLOR: maroon">.</span>SearchScope<span style="FONT-WEIGHT: bold; COLOR: maroon">.</span>Subtree,
</p>
          <p style="MARGIN: 0px">
            attribs
</p>
          <p style="MARGIN: 0px">
            );
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
    PageResultRequestControl prc <span style="FONT-WEIGHT: bold; COLOR: maroon">=</span><span style="COLOR: blue">new</span> PageResultRequestControl(500);
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
    <span style="COLOR: green">//add the paging control</span></p>
          <p style="MARGIN: 0px">
    request<span style="FONT-WEIGHT: bold; COLOR: maroon">.</span>Controls<span style="FONT-WEIGHT: bold; COLOR: maroon">.</span>Add(prc);
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
    <span style="COLOR: blue">while</span> (<span style="COLOR: blue">true</span>)
</p>
          <p style="MARGIN: 0px">
    {
</p>
          <p style="MARGIN: 0px">
        SearchResponse response <span style="FONT-WEIGHT: bold; COLOR: maroon">=</span> connection<span style="FONT-WEIGHT: bold; COLOR: maroon">.</span>SendRequest(request) <span style="COLOR: blue">as</span> SearchResponse;
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: green">//find the returned
page response control</span></p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">foreach</span> (DirectoryControl
control <span style="COLOR: blue">in</span> response<span style="FONT-WEIGHT: bold; COLOR: maroon">.</span>Controls)
</p>
          <p style="MARGIN: 0px">
        {
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">if</span> (control <span style="COLOR: blue">is</span> PageResultResponseControl)
</p>
          <p style="MARGIN: 0px">
            {
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: green">//update
the cookie for next set</span></p>
          <p style="MARGIN: 0px">
                prc<span style="FONT-WEIGHT: bold; COLOR: maroon">.</span>Cookie <span style="FONT-WEIGHT: bold; COLOR: maroon">=</span> ((PageResultResponseControl)control)<span style="FONT-WEIGHT: bold; COLOR: maroon">.</span>Cookie;
</p>
          <p style="MARGIN: 0px">
                <span style="COLOR: blue">break</span>;
</p>
          <p style="MARGIN: 0px">
            }
</p>
          <p style="MARGIN: 0px">
        }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: green">//add them to our
collection</span></p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">foreach</span> (SearchResultEntry
sre <span style="COLOR: blue">in</span> response<span style="FONT-WEIGHT: bold; COLOR: maroon">.</span>Entries)
</p>
          <p style="MARGIN: 0px">
        {
</p>
          <p style="MARGIN: 0px">
            results<span style="FONT-WEIGHT: bold; COLOR: maroon">.</span>Add(sre);
</p>
          <p style="MARGIN: 0px">
        }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
        <span style="COLOR: green">//our exit condition
is when our cookie is empty</span></p>
          <p style="MARGIN: 0px">
        <span style="COLOR: blue">if</span> (prc<span style="FONT-WEIGHT: bold; COLOR: maroon">.</span>Cookie<span style="FONT-WEIGHT: bold; COLOR: maroon">.</span>Length <span style="FONT-WEIGHT: bold; COLOR: maroon">==</span> 0)
</p>
          <p style="MARGIN: 0px">
            <span style="COLOR: blue">break</span>;
</p>
          <p style="MARGIN: 0px">
    }
</p>
          <p style="MARGIN: 0px">
 
</p>
          <p style="MARGIN: 0px">
    <span style="COLOR: blue">return</span> results;
</p>
          <p style="MARGIN: 0px">
}
</p>
        </div>
        <!--EndFragment-->
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=1707c3e7-5395-45f4-8882-3a17f291934b" />
      </body>
      <title>Paging in System.DirectoryServices.Protocols</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,1707c3e7-5395-45f4-8882-3a17f291934b.aspx</guid>
      <link>http://dunnry.com/blog/2006/03/17/PagingInSystemDirectoryServicesProtocols.aspx</link>
      <pubDate>Fri, 17 Mar 2006 20:53:04 GMT</pubDate>
      <description>&lt;p&gt;
One of the new features of .NET 2.0 is the System.DirectoryServices.Protocols (SDS.P)
namespace that gives us access to the native LDAP api without relying on ADSI.&amp;nbsp;
We can accomplish pretty much anything now in LDAP using managed code and we get around
some of the wonkiness of ADSI.
&lt;/p&gt;
&lt;p&gt;
Performing a simple search in SDS.P is pretty straightforward actually.&amp;nbsp; We just
create a connection to the directory using the LdapConnection class, bind to the connection
and then make request/response pairs on the connection.&amp;nbsp; One of the request/response
pairs is SearchRequest and SearchResponse.&amp;nbsp; Without going into too many details,
using these two classes in a synchronous manner is pretty easy.&amp;nbsp; What might be
surprising however is that&amp;nbsp;developers will often run into the following error:
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New" size="2"&gt;System.DirectoryServices.Protocols.DirectoryOperationException
: The size limit was exceeded&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
This departs from System.DirectoryServices (SDS) and ADSI where we do not get errors
for simple searches even if we have not enabled paging.&amp;nbsp; In SDS, a similar query
with DirectorySearcher would just return the MaxPageSize for the directory (usually
1000).&amp;nbsp; We know from SDS that to get more than the MaxPageSize, we need to use
paging.&amp;nbsp; That is as simple as setting DirectorySearcher.PageSize &amp;gt; 0.
&lt;/p&gt;
&lt;p&gt;
So, what about SDS.P.&amp;nbsp; It turns out that one of the really nice things that ADSI
did for us was make paging so seamless.&amp;nbsp; If we wanted to use it, we simply asked
for a specific page size and it just worked.&amp;nbsp; Now, since we are at a lower level,
we need to take care of these details ourselves (native LDAP programmers already know
this of course).
&lt;/p&gt;
&lt;p&gt;
How do we do this in SDS.P?&amp;nbsp; Here is some sample code that implements paging
and returns a collection of SearchResultEntry objects.
&lt;/p&gt;
&lt;div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 8pt; BACKGROUND: white; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: black; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Lucida Console"&gt;
&lt;p style="MARGIN: 0px"&gt;
&lt;span style="COLOR: blue"&gt;private&lt;/span&gt; List&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;&amp;lt;&lt;/span&gt;SearchResultEntry&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;&amp;gt;&lt;/span&gt; PerformPagedSearch(
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; LdapConnection connection,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; baseDN,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; filter,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt;[] attribs)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; List&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;&amp;lt;&lt;/span&gt;SearchResultEntry&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;&amp;gt;&lt;/span&gt; results &lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;=&lt;/span&gt; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; List&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;&amp;lt;&lt;/span&gt;SearchResultEntry&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;&amp;gt;&lt;/span&gt;();
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SearchRequest request &lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;=&lt;/span&gt; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; SearchRequest(
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; baseDN,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; filter,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; System&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;.&lt;/span&gt;DirectoryServices&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;.&lt;/span&gt;Protocols&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;.&lt;/span&gt;SearchScope&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;.&lt;/span&gt;Subtree,
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; attribs
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; );
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; PageResultRequestControl prc &lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;=&lt;/span&gt; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; PageResultRequestControl(500);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//add the paging control&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; request&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;.&lt;/span&gt;Controls&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;.&lt;/span&gt;Add(prc);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;while&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;true&lt;/span&gt;)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SearchResponse response &lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;=&lt;/span&gt; connection&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;.&lt;/span&gt;SendRequest(request) &lt;span style="COLOR: blue"&gt;as&lt;/span&gt; SearchResponse;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//find the returned
page response control&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt; (DirectoryControl
control &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; response&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;.&lt;/span&gt;Controls)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (control &lt;span style="COLOR: blue"&gt;is&lt;/span&gt; PageResultResponseControl)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//update
the cookie for next set&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; prc&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;.&lt;/span&gt;Cookie &lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;=&lt;/span&gt; ((PageResultResponseControl)control)&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;.&lt;/span&gt;Cookie;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;break&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//add them to our
collection&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt; (SearchResultEntry
sre &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; response&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;.&lt;/span&gt;Entries)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; results&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;.&lt;/span&gt;Add(sre);
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: green"&gt;//our exit condition
is when our cookie is empty&lt;/span&gt;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (prc&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;.&lt;/span&gt;Cookie&lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;.&lt;/span&gt;Length &lt;span style="FONT-WEIGHT: bold; COLOR: maroon"&gt;==&lt;/span&gt; 0)
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;break&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; results;
&lt;/p&gt;
&lt;p style="MARGIN: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=1707c3e7-5395-45f4-8882-3a17f291934b" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,1707c3e7-5395-45f4-8882-3a17f291934b.aspx</comments>
      <category>.NET</category>
      <category>LDAP</category>
      <category>Protocols</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=02fa8c85-724e-44c1-ba9d-9392813bb9f9</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,02fa8c85-724e-44c1-ba9d-9392813bb9f9.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,02fa8c85-724e-44c1-ba9d-9392813bb9f9.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=02fa8c85-724e-44c1-ba9d-9392813bb9f9</wfw:commentRss>
      <title>Four things...</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,02fa8c85-724e-44c1-ba9d-9392813bb9f9.aspx</guid>
      <link>http://dunnry.com/blog/2006/03/10/FourThings.aspx</link>
      <pubDate>Fri, 10 Mar 2006 21:31:36 GMT</pubDate>
      <description>&lt;p&gt;
Fellow Avanade&amp;rsquo;r &lt;a href="http://nino.net/blogs/nino/default.aspx"&gt;Nino&lt;/a&gt; seems
to have &amp;lsquo;tagged&amp;rsquo; me for this four things game.&amp;nbsp; Well&amp;hellip; here
goes:
&lt;/p&gt;
&lt;p&gt;
Four Jobs I&amp;rsquo;ve had&amp;hellip;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Target Store stock boy 
&lt;li&gt;
MS Access Developer (during college) 
&lt;li&gt;
Ford Intern for IT department 
&lt;li&gt;
Management Consultant&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Four movies I can watch over and over&amp;hellip;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
The Big Lebowski 
&lt;li&gt;
Office Space 
&lt;li&gt;
Fight Club 
&lt;li&gt;
Groundhog Day&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Four TV shows I love to watch&amp;hellip;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Scrubs 
&lt;li&gt;
Mythbusters 
&lt;li&gt;
Battlestar Galactica 
&lt;li&gt;
Modern Marvels&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Four places I&amp;rsquo;ve been on vacation&amp;hellip;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Maui, Kauai, HI 
&lt;li&gt;
Australia (all over), New Zealand (all over) 
&lt;li&gt;
Greece (Hydra, Mykonos, Santorini) 
&lt;li&gt;
Grand Cayman Island&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Four favorite dishes&amp;hellip;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Cutthroat Salmon (Shucker&amp;rsquo;s) 
&lt;li&gt;
Porterhouse Steak (Hyde Park or Metropolitan Grill) 
&lt;li&gt;
Duck (Wild Ginger)&lt;/li&gt;
&lt;li&gt;
Sushi (best is in Seattle and Hawaii)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Four websites I visit daily:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://forums.asp.net/"&gt;ASP.NET Forums &lt;/a&gt;(LDAP forum) 
&lt;li&gt;
&lt;a href="http://www.hardocp.com/"&gt;HardOcp&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.anandtech.com/"&gt;Anandtech&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.betanews.com/"&gt;Betanews&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Four places I&amp;rsquo;d rather be&amp;hellip;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
On vacation 
&lt;li&gt;
At a bar 
&lt;li&gt;
In an electronics store 
&lt;li&gt;
relaxing with my wife anywhere&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Four bloggers I&amp;rsquo;m tagging
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a title="Keith's blog" href="http://pluralsight.com/blogs/keith/"&gt;Keith&lt;/a&gt;&amp;nbsp;(security
guy extraordinaire) 
&lt;li&gt;
&lt;a title="Cole's blog" href="http://colefrancis3.blogspot.com/"&gt;Cole&lt;/a&gt;&amp;nbsp;(general
super stud) 
&lt;li&gt;
&lt;a title="Joe's blog" href="http://blog.joeware.net/"&gt;Joe&lt;/a&gt;&amp;nbsp;(besides being
an LDAP/AD guru, he&amp;rsquo;s got a lot of opinions&amp;hellip; which&amp;nbsp;I love reading) 
&lt;li&gt;
&lt;a title="Ulf's blog" href="http://msmvps.com/blogs/ulfbsimonweidner/default.aspx"&gt;Ulf&lt;/a&gt;&amp;nbsp;(another
AD guru and all around nice guy)&lt;/li&gt;
&lt;/ul&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=02fa8c85-724e-44c1-ba9d-9392813bb9f9" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,02fa8c85-724e-44c1-ba9d-9392813bb9f9.aspx</comments>
      <category>.NET</category>
      <category>Personal</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=e1d08e6e-5c4f-4ef5-b5a5-853a831a92e6</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,e1d08e6e-5c4f-4ef5-b5a5-853a831a92e6.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,e1d08e6e-5c4f-4ef5-b5a5-853a831a92e6.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=e1d08e6e-5c4f-4ef5-b5a5-853a831a92e6</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <title>Goodbye Messenger BETA</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,e1d08e6e-5c4f-4ef5-b5a5-853a831a92e6.aspx</guid>
      <link>http://dunnry.com/blog/2006/03/09/GoodbyeMessengerBETA.aspx</link>
      <pubDate>Thu, 09 Mar 2006 17:40:38 GMT</pubDate>
      <description>&lt;p&gt;
Like other suckers, I installed the new MSN Messenger BETA 8 (why beta is in all caps
I don&amp;rsquo;t know, perhaps to emphasize its inherent bugginess).&amp;nbsp; After using
it for several weeks, I have given it the boot.&amp;nbsp; Why?
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
I am not a fan of 80+ MB memory footprints for I-frickin-M clients.&lt;/li&gt;
&lt;li&gt;
It crashes during the middle of chats constantly (yeah, I know its BETA with a capital
B, but I wasn&amp;rsquo;t using fancy features here folks).&lt;/li&gt;
&lt;li&gt;
Waaaay too busy an interface for me.&amp;nbsp; I don&amp;rsquo;t dig adverts everywhere and
anywhere and all the pop-ups and distractions are frankly just annoying.&amp;nbsp; It
is not easily evident on how to turn all that crap off and I am not about to spend
an hour (let alone 10 minutes) testing each and every option to figure out what it
means.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
I don&amp;rsquo;t like the way this beta product is leaning.&amp;nbsp; Part of the reason
I used to like Messenger was because it was light, clean interface, and easy to use
(contrast that to the horrible AOL client).&amp;nbsp; It had file transfer, voice and
video capabilities, and the chat client worked well.&amp;nbsp; I don&amp;rsquo;t need games,
winks, farts, tweaks, tickles, or whatever other stupid term is coined for annoying
crap bouncing on your screen.
&lt;/p&gt;
&lt;p&gt;
I am back to the older client and I will hang onto it for dear life until Messenger
goes back to the basics:&amp;nbsp; Improve voice and video, file transfer, and mobile
options for chat.&amp;nbsp; Stop the clutter and useless features (or at least let me
not install the crap).&amp;nbsp; Enough ranting&amp;hellip; back to work.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=e1d08e6e-5c4f-4ef5-b5a5-853a831a92e6" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,e1d08e6e-5c4f-4ef5-b5a5-853a831a92e6.aspx</comments>
      <category>.NET</category>
      <category>Rants</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=87dab34b-846f-483b-a7bd-fbffb5d6e8a9</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,87dab34b-846f-483b-a7bd-fbffb5d6e8a9.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,87dab34b-846f-483b-a7bd-fbffb5d6e8a9.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=87dab34b-846f-483b-a7bd-fbffb5d6e8a9</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <title>Copyedit Complete!</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,87dab34b-846f-483b-a7bd-fbffb5d6e8a9.aspx</guid>
      <link>http://dunnry.com/blog/2006/02/14/CopyeditComplete.aspx</link>
      <pubDate>Tue, 14 Feb 2006 02:39:39 GMT</pubDate>
      <description>&lt;p&gt;
A major milestone was reached today.&amp;nbsp; My co-author, Joe Kaplan, and I have finally
finished the copyedit process for &lt;a href="http://www.amazon.com/gp/product/0321350170/sr=8-1/qid=1139877384/103-3631395-5788633"&gt;our
book&lt;/a&gt;.&amp;nbsp; This has been a very long book in the making and we are both pretty
excited that the end is near.&amp;nbsp; We still have a few more rounds to go with proofs
and what not, but for the most part, it is all done.&amp;nbsp; The next big focus for
us will be to get the companion web site in order.&amp;nbsp; I won&amp;rsquo;t share the URL
for it yet, but it should have some great code that we developed for this book to
share.
&lt;/p&gt;
&lt;p&gt;
If&amp;nbsp;anyone was wondering why I have not been in the &lt;a href="http://forums.asp.net/"&gt;forums &lt;/a&gt;as
much as normal these last few weeks, its because we have been heads down trying to
get this all wrapped up.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=87dab34b-846f-483b-a7bd-fbffb5d6e8a9" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,87dab34b-846f-483b-a7bd-fbffb5d6e8a9.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
      <category>Book</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=4a70bd0d-4392-4a16-92e0-f7565e5dae64</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,4a70bd0d-4392-4a16-92e0-f7565e5dae64.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,4a70bd0d-4392-4a16-92e0-f7565e5dae64.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=4a70bd0d-4392-4a16-92e0-f7565e5dae64</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <title>Strange DasBlog Error Fixed</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,4a70bd0d-4392-4a16-92e0-f7565e5dae64.aspx</guid>
      <link>http://dunnry.com/blog/2006/01/26/StrangeDasBlogErrorFixed.aspx</link>
      <pubDate>Thu, 26 Jan 2006 05:48:42 GMT</pubDate>
      <description>&lt;p&gt;
&lt;a href="http://dunnry.com/blog/StrangeDasBlogError.aspx"&gt;Previously &lt;/a&gt;I was getting
an intermittent error with DasBlog that would cause the entire site to freeze up.&amp;nbsp; &lt;a href="http://www.hanselman.com/blog/"&gt;Scott
Hanselman &lt;/a&gt;was kind enough to point out the bug and suggest that I upgrade the
binaries to fix it:
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;&amp;ldquo;This happens if, IMMEDIATELY FOLLOWING AN APP RECYCLE, a category page
is hit, rather than a page in the root. The HttpModule thinks that the AppDomain is
starting up with the category page as it's root and chaos ensues.&amp;rdquo;&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
I have been waiting a few weeks to ensure that this patch indeed fixed it, and it
appears to be golden now.
&lt;/p&gt;
&lt;p&gt;
Thanks Scott!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=4a70bd0d-4392-4a16-92e0-f7565e5dae64" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,4a70bd0d-4392-4a16-92e0-f7565e5dae64.aspx</comments>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>DasBlog</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=a085c53d-bbd2-43c7-8b76-d8825dbb6973</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,a085c53d-bbd2-43c7-8b76-d8825dbb6973.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,a085c53d-bbd2-43c7-8b76-d8825dbb6973.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=a085c53d-bbd2-43c7-8b76-d8825dbb6973</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Well, it was bound to happen.  I was using free .NET 2.0 beta hosting and the
account was expiring.  I had to switch servers and providers in order to keep
my mail and site intact.  Now that that transistion has occurred, hopefully I
will get around to posting some more interesting tidbits.
</p>
        <p>
 
</p>
        <img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=a085c53d-bbd2-43c7-8b76-d8825dbb6973" />
      </body>
      <title>Back online</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,a085c53d-bbd2-43c7-8b76-d8825dbb6973.aspx</guid>
      <link>http://dunnry.com/blog/2006/01/16/BackOnline.aspx</link>
      <pubDate>Mon, 16 Jan 2006 19:28:23 GMT</pubDate>
      <description>&lt;p&gt;
Well, it was bound to happen.&amp;nbsp; I was using free .NET 2.0 beta hosting and the
account was expiring.&amp;nbsp; I had to switch servers and providers in order to keep
my mail and site intact.&amp;nbsp; Now that that transistion has occurred, hopefully I
will get around to posting some more interesting tidbits.
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=a085c53d-bbd2-43c7-8b76-d8825dbb6973" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,a085c53d-bbd2-43c7-8b76-d8825dbb6973.aspx</comments>
      <category>.NET</category>
      <category>ASP.NET</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=c8e2b36f-46f2-4d5d-ba8d-247566281405</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,c8e2b36f-46f2-4d5d-ba8d-247566281405.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,c8e2b36f-46f2-4d5d-ba8d-247566281405.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c8e2b36f-46f2-4d5d-ba8d-247566281405</wfw:commentRss>
      <title>WMF Exploit Firsthand</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,c8e2b36f-46f2-4d5d-ba8d-247566281405.aspx</guid>
      <link>http://dunnry.com/blog/2005/12/31/WMFExploitFirsthand.aspx</link>
      <pubDate>Sat, 31 Dec 2005 23:04:52 GMT</pubDate>
      <description>&lt;p&gt;
The last few days have been pretty crappy with regards to the computer situation.&amp;nbsp;
On Wednesday (the 27th), I was trying to recover some files from a portable harddrive
that had decided to go tits-up.&amp;nbsp; Well, the short story is that I was browsing
the web using Google cache and all of the sudden my AV package and MS Antispyware
went crazy.&amp;nbsp; Something was dropping trojans onto my machine at an alarming rate.&amp;nbsp;
This was before all the hubbub broke out the next day describing the issue.
&lt;/p&gt;
&lt;p&gt;
I spent an inordinate amount of time trying to undo all the hooks that had been put
into my XP SP2 (fully patched) box.&amp;nbsp; First, I found that my firewall had been
disabled, group policy had been applied to prevent me from accessing the task manager,
and a bunch of stuff was injected into my startup portions in the registry.
&lt;/p&gt;
&lt;p&gt;
Using &lt;a href="http://www.sysinternals.com/Utilities/Autoruns.html"&gt;Autoruns &lt;/a&gt;and &lt;a href="http://www.sysinternals.com/Utilities/ProcessExplorer.html"&gt;Process
Explorer&lt;/a&gt;, I also discovered that my Explorer.exe had been replaced and shelled
out by another program that was trying to prevent me from removing the trojan(s).&amp;nbsp;
A number of unknown services were installed and all of my browser settings were hijacked
(no help from Antispyware there for some reason).&amp;nbsp; A static HTML page was inserted
as my homepage that told me that my computer was at risk from spyware.&amp;nbsp; I suspect
the idiots that wrote the malware expected me to take them up on an offer to remove
it.
&lt;/p&gt;
&lt;p&gt;
I was able to undo all the hooks and set the system in order, but I was not comfortable
that I got every last thing.&amp;nbsp; As such, I had to back up a few files I was working
on and restore a backup image I luckily had.&amp;nbsp; This took me a few days with everything
else I had going on.
&lt;/p&gt;
&lt;p&gt;
The points that bother me are:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
I don&amp;rsquo;t think running as&amp;nbsp;lower privilege user would have helped (yes, I
run as an Admin, bad Ryan).&amp;nbsp; It appears that this is using a buffer overflow
and RevertToSelf()&amp;nbsp;to get to SYSTEM account.&amp;nbsp; Perhaps I am wrong on this
one, but I have not read anything to contravene this viewpoint as it appears all XP
machines are vulnerable regardless of setup.&amp;nbsp; I got this from Google&amp;rsquo;s
cache, not by clicking or running any files.&lt;/li&gt;
&lt;li&gt;
MS Antispyware was easily defeated.&amp;nbsp; It did notify me that a trojan was installed
and tried to let me remove it (which it said it did, but did not).&amp;nbsp; It did not
protect me from any of my settings being hijacked.&amp;nbsp; That was a big miss.&amp;nbsp;
Not only that, but I could not restore my old settings since the trojan wiped them
as well.&lt;/li&gt;
&lt;li&gt;
My AV package did not help either.&amp;nbsp; It was nice enough to let me know that trojans
were being installed, but did not appear to prevent it either.&amp;nbsp; What was the
point of that?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
This is a really bad one folks.&amp;nbsp; This is the very first time I have ever been
infected or compromised.&amp;nbsp; I shudder to think how easily it occurred.&amp;nbsp; Make
sure you patch up.&amp;nbsp; There is an &lt;a href="http://www.hexblog.com/2005/12/wmf_vuln.html"&gt;unofficial
patch &lt;/a&gt;you can use right now to help.
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=c8e2b36f-46f2-4d5d-ba8d-247566281405" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,c8e2b36f-46f2-4d5d-ba8d-247566281405.aspx</comments>
      <category>.NET</category>
      <category>Security</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=97b61585-83ad-4887-ac9c-db56c0bf92c4</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,97b61585-83ad-4887-ac9c-db56c0bf92c4.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,97b61585-83ad-4887-ac9c-db56c0bf92c4.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=97b61585-83ad-4887-ac9c-db56c0bf92c4</wfw:commentRss>
      <title>Resurrecting Tombstones in Active Directory or ADAM</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,97b61585-83ad-4887-ac9c-db56c0bf92c4.aspx</guid>
      <link>http://dunnry.com/blog/2005/12/22/ResurrectingTombstonesInActiveDirectoryOrADAM.aspx</link>
      <pubDate>Thu, 22 Dec 2005 18:13:47 GMT</pubDate>
      <description>&lt;p&gt;
I did not get to put all the material I wanted to into the book, so I figure some
of the stuff we have left out will make good material for a blog entry here and there.
&lt;/p&gt;
&lt;p&gt;
Active Directory and ADAM both have a special container called &amp;ldquo;CN=Deleted Objects&amp;rdquo;
that can only be viewed by administrators by default.&amp;nbsp; When we delete objects
in either of these directories, the entries are typically moved there and most of
their attributes are stripped off.&amp;nbsp; This is done such that other replication
partners know which items were deleted.&amp;nbsp; These objects are now referred to as
&amp;lsquo;tombstones&amp;rsquo;.&amp;nbsp; The system will hold these objects for a set period
of time (60 days or so IIRC) before purging them completely.
&lt;/p&gt;
&lt;p&gt;
Now, occasionally we run into situations where we want to resurrect one of the tombstones.&amp;nbsp;
This is typically when we need an object to have the identical GUID or SID it had
while alive as simply recreating the object would generate new values for these attributes.&amp;nbsp;
There is an example on MSDN on how to resurrect these objects, but it is in C++.&amp;nbsp;
I thought it would be fun to show how to do this in System.DirectoryServices.Protocols
as it has the capabilities to do this while System.DirectoryServices (ADSI) does not.&amp;nbsp;
We have to use the LDAP replace method in this case which is supported in the new
Protocols namespace.
&lt;/p&gt;
&lt;p&gt;
Instead of just posting a link to my code, I thought I would post it in whole here.&amp;nbsp;
Notice that my Lazarus (resurrected, get it?) class is using Well-known GUID binding.&amp;nbsp;
You should have your RootDSE return a defaultNamingContext for ADAM if you have not
already done so.
&lt;/p&gt;
&lt;pre style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 9pt; BACKGROUND: white; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: black; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Lucida Console"&gt;&lt;span style="COLOR: blue"&gt;class&lt;/span&gt; Lazarus
: IDisposable { &lt;span style="COLOR: blue"&gt;const&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; WK_TOMBSTONE
= "18e2ea80684f11d2b9aa00c04f79f805"; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; _defaultNC; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; _server;
DirectoryEntry _entry; &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; Lazarus() : &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;(&lt;span style="COLOR: blue"&gt;null&lt;/span&gt;)
{ } &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; Lazarus(&lt;span style="COLOR: blue"&gt;string&lt;/span&gt; server)
{ _server = server; DirectoryEntry root = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; DirectoryEntry(
String.Format( "LDAP://{0}RootDSE", _server != &lt;span style="COLOR: blue"&gt;null&lt;/span&gt; ?
_server + "/" : String.Empty ) ); &lt;span style="COLOR: blue"&gt;using&lt;/span&gt; (root) {
_defaultNC = root.Properties["defaultNamingContext"][0].ToString(); } _entry = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; DirectoryEntry(
String.Format( "LDAP://{0}&amp;lt;WKGUID={1},{2}&amp;gt;", _server != &lt;span style="COLOR: blue"&gt;null&lt;/span&gt; ?
_server + "/" : String.Empty, WK_TOMBSTONE, _defaultNC ), &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;, &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;,
AuthenticationTypes.Secure | AuthenticationTypes.FastBind ); } &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; ShowAllTombStones()
{ DirectorySearcher ds = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; DirectorySearcher( _entry,
"(isDeleted=TRUE)", &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;, System.DirectoryServices.SearchScope.OneLevel
); ds.PageSize = 1000; ds.Tombstone = &lt;span style="COLOR: blue"&gt;true&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;using&lt;/span&gt; (SearchResultCollection
src = ds.FindAll()) { &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt; (SearchResult sr &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; src)
{ &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;string&lt;/span&gt; key &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; sr.Properties.PropertyNames)
{ &lt;span style="COLOR: blue"&gt;foreach&lt;/span&gt; (&lt;span style="COLOR: blue"&gt;object&lt;/span&gt; o &lt;span style="COLOR: blue"&gt;in&lt;/span&gt; sr.Properties[key])
{ Console.WriteLine("{0}: {1}", key, o); } } Console.WriteLine("====================");
} } } &lt;span style="COLOR: blue"&gt;private&lt;/span&gt; SearchResult GetTombstone(&lt;span style="COLOR: blue"&gt;string&lt;/span&gt; name)
{ DirectorySearcher ds = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; DirectorySearcher( _entry,
String.Format("(&amp;amp;(isDeleted=TRUE)(name={0}*))", name), &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt;[]
{ "cn", "lastKnownParent", "distinguishedName" }, System.DirectoryServices.SearchScope.OneLevel
); ds.Tombstone = &lt;span style="COLOR: blue"&gt;true&lt;/span&gt;; &lt;span style="COLOR: blue"&gt;return&lt;/span&gt; ds.FindOne();
} &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; RaiseFromTheDead(&lt;span style="COLOR: blue"&gt;string&lt;/span&gt; name)
{ SearchResult deadGuy = GetTombstone(name); &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (deadGuy
== &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;) &lt;span style="COLOR: blue"&gt;throw&lt;/span&gt; &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; ArgumentException("No
object exists"); LdapConnection conn = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; LdapConnection( &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; LdapDirectoryIdentifier(_server),
System.Net.CredentialCache.DefaultNetworkCredentials, AuthType.Negotiate ); &lt;span style="COLOR: blue"&gt;using&lt;/span&gt; (conn)
{ conn.Bind(); conn.SessionOptions.ProtocolVersion = 3; &lt;span style="COLOR: green"&gt;//we
have to remove the isDELETED attribute&lt;/span&gt; DirectoryAttributeModification dam = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; DirectoryAttributeModification();
dam.Name = "isDELETED"; dam.Operation = DirectoryAttributeOperation.Delete; &lt;span style="COLOR: green"&gt;//and
set a new dn string - a bit of a copout because&lt;/span&gt; &lt;span style="COLOR: green"&gt;//I
am always assuming a CN prefix.&lt;/span&gt; &lt;span style="COLOR: blue"&gt;string&lt;/span&gt; newDN
= String.Format( "CN={0},{1}", deadGuy.Properties["cn"][0].ToString().Split(&lt;span style="COLOR: blue"&gt;new&lt;/span&gt; &lt;span style="COLOR: blue"&gt;char&lt;/span&gt;[]{'\n'})[0],
deadGuy.Properties["lastKnownParent"][0] ); &lt;span style="COLOR: green"&gt;//word of warning...
'lastKnownParent' is only guaranteed good&lt;/span&gt; &lt;span style="COLOR: green"&gt;//on Windows
Server 2003 and ADAM.&lt;/span&gt; DirectoryAttributeModification dam2 = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; DirectoryAttributeModification();
dam2.Name = "distinguishedName"; dam2.Operation = DirectoryAttributeOperation.Replace;
dam2.Add(newDN); &lt;span style="COLOR: green"&gt;//kinda bizzare that a collection is not
used&lt;/span&gt; ModifyRequest mr = &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; ModifyRequest(
deadGuy.Properties["distinguishedName"][0].ToString(), &lt;span style="COLOR: blue"&gt;new&lt;/span&gt; DirectoryAttributeModification[]
{ dam, dam2 } ); &lt;span style="COLOR: green"&gt;//we need to have the ShowDeletedControl
to find this DN&lt;/span&gt; mr.Controls.Add(&lt;span style="COLOR: blue"&gt;new&lt;/span&gt; ShowDeletedControl()); &lt;span style="COLOR: green"&gt;//optionally,
we must put any required attributes on the object&lt;/span&gt; &lt;span style="COLOR: green"&gt;//as
well. For user/computer, this might be 'sAMAccountName'&lt;/span&gt; ModifyResponse resp
= (ModifyResponse)conn.SendRequest(mr); &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (resp.ResultCode
!= ResultCode.Success) { &lt;span style="COLOR: green"&gt;//we should also check to see
if it was already&lt;/span&gt; &lt;span style="COLOR: green"&gt;//existing here (same DN).&lt;/span&gt; Console.WriteLine(resp.ErrorMessage);
} } } &lt;span style="COLOR: blue"&gt; #region&lt;/span&gt; IDisposable Members &lt;span style="COLOR: blue"&gt;public&lt;/span&gt; &lt;span style="COLOR: blue"&gt;void&lt;/span&gt; Dispose()
{ &lt;span style="COLOR: blue"&gt;if&lt;/span&gt; (_entry != &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;)
_entry.Dispose(); } &lt;span style="COLOR: blue"&gt; #endregion&lt;/span&gt; } &lt;/pre&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
This is definitely sample code, but it should give a working idea of how to accomplish
this.&amp;nbsp; I think that as I used the .Protocols namespace, there were some usability
issues that I question, however it is definitely a neat addition.&amp;nbsp; I decided
to mix using System.DirectoryServices with using .Protocols because I wanted to show
how to do a Tombstone search using SDS as well.
&lt;/p&gt;
&lt;p&gt;
Finally, this was tested on ADAM, but should work fine on AD.&amp;nbsp; The usual warnings
apply:&amp;nbsp; &lt;em&gt;This is not production code, don&amp;rsquo;t expect it to be and don&amp;rsquo;t
cry to me if it breaks your machine horribly or your dog dies.&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
Enjoy, your comments are always welcome.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=97b61585-83ad-4887-ac9c-db56c0bf92c4" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,97b61585-83ad-4887-ac9c-db56c0bf92c4.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
      <category>Protocols</category>
    </item>
    <item>
      <trackback:ping>http://dunnry.com/blog/Trackback.aspx?guid=c5f57a02-a66a-4ef7-b894-46fd65ce7d26</trackback:ping>
      <pingback:server>http://dunnry.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://dunnry.com/blog/PermaLink,guid,c5f57a02-a66a-4ef7-b894-46fd65ce7d26.aspx</pingback:target>
      <dc:creator>Ryan Dunn</dc:creator>
      <wfw:comment>http://dunnry.com/blog/CommentView,guid,c5f57a02-a66a-4ef7-b894-46fd65ce7d26.aspx</wfw:comment>
      <wfw:commentRss>http://dunnry.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c5f57a02-a66a-4ef7-b894-46fd65ce7d26</wfw:commentRss>
      <title>The .NET Developer's Guide To Directory Services Programming</title>
      <guid isPermaLink="false">http://dunnry.com/blog/PermaLink,guid,c5f57a02-a66a-4ef7-b894-46fd65ce7d26.aspx</guid>
      <link>http://dunnry.com/blog/2005/12/22/TheNETDevelopersGuideToDirectoryServicesProgramming.aspx</link>
      <pubDate>Thu, 22 Dec 2005 17:37:42 GMT</pubDate>
      <description>&lt;p&gt;
&lt;a href="http://pluralsight.com/blogs/keith/archive/2005/12/15/17496.aspx"&gt;Keith beat
me to it&lt;/a&gt;, but Joe and I have finally submitted the final manuscript.&amp;nbsp; We
have some copy editing left, but the book is mostly baked.&amp;nbsp; It has been a long
time in the making and we are very fortunate to have had some great reviewers like
Keith giving us advice along the way.
&lt;/p&gt;
&lt;p&gt;
There were a lot of things that we wished we could have covered (perhaps in another
book) more in depth.&amp;nbsp; It was a balancing act between trying to dump everything
in our brains and not publishing a 900 page book.&amp;nbsp; The final page count is around
450 pages right now, which is big, but not too intimidating.
&lt;/p&gt;
&lt;p&gt;
All in all, this was a good experience.&amp;nbsp; I did not know Joe very well when we
started, but needless to say, we know each pretty well at this point and are good
friends.&amp;nbsp; I think the partnership worked pretty darn well for two first-time
authors collaborating mostly over email and wiki.&amp;nbsp; Joe knows his Directory Services
very well and it would not nearly be the same book without him.&amp;nbsp; Keith was slightly
off in his description (it was over a year ago), but I knew about Joe from the newsgroups
(where he was dropping some serious knowledge) and had suggested to Keith to contact
him as the second author of this book.&amp;nbsp; It was a great decision and I am glad
Joe&amp;nbsp;took it.
&lt;/p&gt;
&lt;p&gt;
So, what is in the book?&amp;nbsp; Pretty much all the basics for System.DirectoryServices,
like binding,&amp;nbsp;searching, reading and writing attributes.&amp;nbsp; We cover the more
advanced searches and data type marshaling as well as schema considerations and a
discussion of security as well.&amp;nbsp; Finally, we cover a more scenario, or &amp;lsquo;cookbook&amp;rsquo;
approach for the more popular topics like user and group management as well as authentication.&amp;nbsp;
We know what problems most users have and we try to address them in the scenarios.
&lt;/p&gt;
&lt;p&gt;
Most of the samples in the book are going to be using System.DirectoryServices, though
we do cover in places how to do things using the .Protocols namespace.&amp;nbsp; Additionally,
we have one chapter that gives developers a view of what is there in the .ActiveDirectory
namespace that they might use (it is mostly for administrators).
&lt;/p&gt;
&lt;p&gt;
It is important to know that this is truly a guide and we could not cover every single
scenario.&amp;nbsp; As part of the book&amp;rsquo;s website (or this blog), we will be adding
new scenarios and how they can be accomplished as well.&amp;nbsp; Additionally, we are
going to release some very cool code that developers will be able to use in their
own applications.
&lt;/p&gt;
&lt;p&gt;
As always, we can be found in either the forums (&lt;a href="http://forums.asp.net/"&gt;http://forums.asp.net&lt;/a&gt;)
or the newsgroups (microsoft.public.adsi.general).&amp;nbsp; I am not usually on the newsgroups,
but Joe camps there.
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://dunnry.com/blog/aggbug.ashx?id=c5f57a02-a66a-4ef7-b894-46fd65ce7d26" /&gt;</description>
      <comments>http://dunnry.com/blog/CommentView,guid,c5f57a02-a66a-4ef7-b894-46fd65ce7d26.aspx</comments>
      <category>.NET</category>
      <category>ADSI</category>
      <category>LDAP</category>
      <category>Tips</category>
    </item>
  </channel>
</rss>