<?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:wfw="http://wellformedweb.org/CommentAPI/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" version="2.0">
  <channel>
    <title>Paul Mrozowski's Blog - .NET</title>
    <link>http://www.rcs-solutions.com/blog/</link>
    <description>A day in the life (of a developer)</description>
    <language>en-us</language>
    <copyright>Paul Mrozowski / RCS Solutions, Inc.</copyright>
    <lastBuildDate>Wed, 24 Nov 2010 01:54:04 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.0.7226.0</generator>
    <managingEditor>paulm@rcs-solutions.com</managingEditor>
    <webMaster>paulm@rcs-solutions.com</webMaster>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=c3498c80-09ad-42a8-a4e0-6e7f03caceb0</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,c3498c80-09ad-42a8-a4e0-6e7f03caceb0.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,c3498c80-09ad-42a8-a4e0-6e7f03caceb0.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c3498c80-09ad-42a8-a4e0-6e7f03caceb0</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
A few years ago I needed the ability to “autolink” text – basically, I had a list
of keywords and anytime those keywords were displayed on a page I needed to have them
turned into a link. The code is relatively straightforward, but I thought it might
be of some use to other people.
</p>
        <pre style="background-color: #f7f7f7; font-family: ">
          <font face="Consolas">
            <span>
              <font color="#0000ff">
                <font style="font-size: 12pt">using</font>
              </font>
            </span>
            <font style="font-size: 12pt"> System;<br /><span><font color="#0000ff">using</font></span> System.Collections.Generic;<br /><span><font color="#0000ff">using</font></span> System.Linq;<br /><span><font color="#0000ff">using</font></span> System.Text;<br /><span><font color="#0000ff">using</font></span> System.Text.RegularExpressions;<br /><br /><span><font color="#0000ff">namespace</font></span> RCSSolutions<br />
{<br />
    <span><font color="#0000ff">public</font></span> <span><font color="#0000ff">class</font></span> <span><font color="#2b91af">Term</font></span><br />
    {<br />
        <span><font color="#0000ff">public</font></span> <span><font color="#0000ff">string</font></span> LinkTerm
{ <span><font color="#0000ff">get</font></span>; <span><font color="#0000ff">set</font></span>;
}        
<br />
        <span><font color="#0000ff">public</font></span> <span><font color="#0000ff">string</font></span> Url
{ <span><font color="#0000ff">get</font></span>; <span><font color="#0000ff">set</font></span>;
}<br />
        <span><font color="#0000ff">public</font></span> <span><font color="#0000ff">string</font></span> Target
{ <span><font color="#0000ff">get</font></span>; <span><font color="#0000ff">set</font></span>;
}<br />
    }<br /><br />
    <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><span><font color="#808080">&lt;summary&gt;</font></span><br />
    <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> Adds
links to a passed in string based on records in</font></span><br />
    <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> the
SourceAutolink table.</font></span><br />
    <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><span><font color="#808080">&lt;/summary&gt;</font></span><br />
    <span><font color="#0000ff">public</font></span> <span><font color="#0000ff">class</font></span> <span><font color="#2b91af">AutoLinker</font></span><br />
    {             
<br />
        <span><font color="#0000ff">private</font></span> <span><font color="#0000ff">string</font></span> m_linkStyle
= <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #e5e5e5">""</font></span>;<br /><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><span><font color="#808080">&lt;summary&gt;</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">List
of words which auto link</font></span><span><font color="#808080">&lt;/summary&gt;</font></span><br />
        <span><font color="#0000ff">public</font></span> <span><font color="#2b91af">List</font></span>&lt;<span><font color="#2b91af">Term</font></span>&gt;
LinkWords { <span><font color="#0000ff">get</font></span>; <span><font color="#0000ff">set</font></span>;
}<br /><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><span><font color="#808080">&lt;summary&gt;</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">The
CSS class to assign to the link tag</font></span><span><font color="#808080">&lt;/summary&gt;</font></span><br />
        <span><font color="#0000ff">public</font></span> <span><font color="#0000ff">string</font></span> LinkStyle<br />
        {<br />
            <span><font color="#0000ff">get</font></span> { <span><font color="#0000ff">return</font></span> <span><font color="#0000ff">this</font></span>.m_linkStyle;
}<br />
            <span><font color="#0000ff">set</font></span> { <span><font color="#0000ff">this</font></span>.m_linkStyle
= <span><font color="#0000ff">value</font></span>; }<br />
        }<br /><br />
        <span><font color="#0000ff">public</font></span> AutoLinker
(<span><font color="#2b91af">List</font></span>&lt;<span><font color="#2b91af">Term</font></span>&gt;
linkWords)<br />
        {<br />
            LinkWords = linkWords;<br />
        }<br /><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><span><font color="#808080">&lt;summary&gt;</font></span><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> Adds
any links to the passed in content.</font></span><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><span><font color="#808080">&lt;/summary&gt;</font></span><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><font color="#808080"><span>&lt;param
name=</span><span>"content"</span><span>&gt;</span></font><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">Content
to evaluate</font></span><span><font color="#808080">&lt;/param&gt;</font></span><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><span><font color="#808080">&lt;returns&gt;</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">Marked
up results</font></span><span><font color="#808080">&lt;/returns&gt;</font></span><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><span><font color="#808080">&lt;developer&gt;</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">Paul
Mrozowski</font></span><span><font color="#808080">&lt;/developer&gt;</font></span><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><span><font color="#808080">&lt;created&gt;</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">07/07/2008</font></span><span><font color="#808080">&lt;/created&gt;</font></span><br />
        <span><font color="#0000ff">public</font></span> <span><font color="#0000ff">string</font></span> AutoLink(<span><font color="#0000ff">string</font></span> content)<br />
        {<br />
            <span><font color="#0000ff">if</font></span> (<span><font color="#0000ff">this</font></span>.LinkWords
== <span><font color="#0000ff">null</font></span>)<br />
                <span><font color="#0000ff">return</font></span> content;<br />
            
<br />
            <span><font color="#2b91af">StringBuilder</font></span> result
= <span><font color="#0000ff">new</font></span> <span><font color="#2b91af">StringBuilder</font></span>();<br /><br />
            <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">//
Replaces HTML (and html-like) tags with spaces (we want to keep</font></span><br />
            <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">//
the same relative positions of everything else in the text since</font></span><br />
            <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">//
we're going to use them to do the final replacements.)</font></span><br />
            <span><font color="#0000ff">string</font></span> newSentence
= <span><font color="#2b91af">Regex</font></span>.Replace(content,<br />
                                     <span><font color="#a31515">@"&lt;(.|\n)*?&gt;"</font></span>,<br />
                                    
match =&gt; <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #e5e5e5">"
"</font></span>.PadRight(match.Length));<br /><br />
            <span><font color="#0000ff">string</font></span> tmpContent
= content;<br /><br />
            <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">//
Loop through each link term, search for matches. Save each of them into a new collection</font></span><br />
            <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">//
We're going to use the results to sort the matches in decending order by location.
That</font></span><br />
            <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">//
way we can perform the replacements w/o moving the starting location of the other
replacements.</font></span><br />
            <span><font color="#0000ff">foreach</font></span> (<span><font color="#0000ff">var</font></span> linkRow <span><font color="#0000ff">in</font></span> LinkWords)<br />
            {<br />
                <span><font color="#0000ff">var</font></span> allMatches
= <span><font color="#0000ff">new</font></span> <span><font color="#2b91af">List</font></span>&lt;<span><font color="#2b91af">Match</font></span>&gt;();<br />
                <span><font color="#2b91af">MatchCollection</font></span> matches
= <span><font color="#2b91af">Regex</font></span>.Matches(newSentence, linkRow.LinkTerm, <span><font color="#2b91af">RegexOptions</font></span>.IgnoreCase);<br />
                <span><font color="#0000ff">foreach</font></span> (<span><font color="#2b91af">Match</font></span> match <span><font color="#0000ff">in</font></span> matches)<br />
                   
allMatches.Add(match);<br /><br />
                <span><font color="#0000ff">var</font></span> orderedMatches
= <span><font color="#0000ff">from</font></span> m <span><font color="#0000ff">in</font></span> allMatches<br />
                                     <span><font color="#0000ff">orderby</font></span> m.Index <span><font color="#0000ff">descending</font></span><br />
                                     <span><font color="#0000ff">select</font></span> m;<br /><br />
                <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">//
General idea is to grab all of the text following the match, get the newly</font></span><br />
                <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">//
link word w/html markup and insert it before the this text. Then truncate</font></span><br />
                <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">//
the original content to remove everything from the starting position of the</font></span><br />
                <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">//
match to the end of file - this is basically done so I don't have to track</font></span><br />
                <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">//
the current position within the file. After we're done with the loop we</font></span><br />
                <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">//
insert anything that's left to the beginning of the new string.</font></span><br />
                <span><font color="#0000ff">foreach</font></span> (<span><font color="#2b91af">Match</font></span> item <span><font color="#0000ff">in</font></span> orderedMatches)<br />
               
{<br />
                    <span><font color="#0000ff">string</font></span> endOfMatchedStringToEOF
= tmpContent.Substring(item.Index + item.Length);<br />
                   
result.Insert(0, GetAutolinkText(linkRow, item.Value) + endOfMatchedStringToEOF);<br />
                   
tmpContent = tmpContent.Substring(0, item.Index);<br />
               
}<br />
            }<br /><br />
            result.Insert(0,
tmpContent);<br /><br />
            <span><font color="#0000ff">return</font></span> result.ToString();<br />
        }<br /><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><span><font color="#808080">&lt;summary&gt;</font></span><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> Get
the replacement text.</font></span><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><span><font color="#808080">&lt;/summary&gt;</font></span><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><font color="#808080"><span>&lt;param
name=</span><span>"token"</span><span>&gt;</span></font><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">Word
token</font></span><span><font color="#808080">&lt;/param&gt;</font></span><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><font color="#808080"><span>&lt;param
name=</span><span>"content"</span><span>&gt;</span></font><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">Original
content</font></span><span><font color="#808080">&lt;/param&gt;</font></span><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><span><font color="#808080">&lt;returns&gt;</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">Empty
string if no replacement</font></span><span><font color="#808080">&lt;/returns&gt;</font></span><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><span><font color="#808080">&lt;developer&gt;</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">Paul
Mrozowski</font></span><span><font color="#808080">&lt;/developer&gt;</font></span><br />
        <span><font color="#808080">///</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf"> </font></span><span><font color="#808080">&lt;created&gt;</font></span><span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">07/08/2008</font></span><span><font color="#808080">&lt;/created&gt;</font></span><br />
        <span><font color="#0000ff">private</font></span> <span><font color="#0000ff">string</font></span> GetAutolinkText(<span><font color="#2b91af">Term</font></span> linkTo, <span><font color="#0000ff">string</font></span> match)<br />
        {<br />
            <span><font color="#0000ff">string</font></span> newWord
= match;<br /><br />
            <span><font color="#0000ff">if</font></span> (<span><font color="#0000ff">this</font></span>.m_linkStyle.Length
== 0)<br />
               
newWord = <span><font color="#0000ff">string</font></span>.Format(<span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #e5e5e5">"&lt;a
href='{0}' "</font></span>, linkTo.Url);<br />
            <span><font color="#0000ff">else</font></span><br />
               
newWord = <span><font color="#0000ff">string</font></span>.Format(<span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #e5e5e5">"&lt;a
class='{0}' href='{1}' "</font></span>, 
<br />
                                        <span><font color="#0000ff">this</font></span>.LinkStyle, 
<br />
                                       
linkTo.Url);<br /><br />
            <span><font color="#0000ff">if</font></span> ((linkTo.Target
?? <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #e5e5e5">""</font></span>).Length
&gt; 0)<br />
               
newWord += <span><font color="#0000ff">string</font></span>.Format(<span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #e5e5e5">"target='{0}'
"</font></span>, linkTo.Target);<br /><br />
            <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #ffffbf">//
We pass in the original match term to maintain its case (the initial match was case-insensitive).</font></span><br />
            newWord += <span><font color="#0000ff">string</font></span>.Format(<span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #e5e5e5">"&gt;{0}&lt;/a&gt;"</font></span>,
match);<br /><br />
            <span><font color="#0000ff">return</font></span> newWord;<br />
        }<br />
    }<br />
}</font>
          </font>
          <br />
        </pre>
        <p>
Usage is simple – create a list of terms that you want linked (along with the URL,
style (if any), and target) and pass it to the AutoLinker class, then call AutoLink
with your source text. It will return the text with the links embedded in it. Here’s
a sample from a console application:
</p>
        <pre>
          <font face="Consolas">
            <font style="font-size: 12pt">        <span><font color="#0000ff">static</font></span> <span><font color="#0000ff">void</font></span> Main(<span><font color="#0000ff">string</font></span>[]
args)<br />
        {<br />
            <span><font color="#0000ff">var</font></span> terms
= <span><font color="#0000ff">new</font></span> <span><font color="#2b91af">List</font></span>&lt;<span><font color="#2b91af">Term</font></span>&gt;();<br />
            terms.Add(<span><font color="#0000ff">new</font></span> <span><font color="#2b91af">Term</font></span>()
{ LinkTerm = <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #e5e5e5">"Hello"</font></span>,
Target = <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #e5e5e5">"_blank"</font></span>,
Url = <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #e5e5e5">"http://www.rcs-solutions.com"</font></span> });<br /><br />
            <span><font color="#0000ff">string</font></span> sentence
= <span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"><font style="background-color: #e5e5e5">"Why,
hello! This is a sentence where I'm going to link to the word \"hello\"."</font></span>;<br />
            <span><font color="#2b91af">Console</font></span>.Write(sentence);<br />
            <span><font color="#0000ff">var</font></span> linker
= <span><font color="#0000ff">new</font></span> <span><font color="#2b91af">AutoLinker</font></span>(terms);<br />
            
<br />
            <span><font color="#2b91af">Console</font></span>.Write(linker.AutoLink(sentence));<br />
            <span><font color="#2b91af">Console</font></span>.ReadKey();<br />
        }</font>
          </font>
        </pre>
        <img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=c3498c80-09ad-42a8-a4e0-6e7f03caceb0" />
      </body>
      <title>Auto Linking Text in a Web Page</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,c3498c80-09ad-42a8-a4e0-6e7f03caceb0.aspx</guid>
      <link>http://www.rcs-solutions.com/blog/2010/11/24/AutoLinkingTextInAWebPage.aspx</link>
      <pubDate>Wed, 24 Nov 2010 01:54:04 GMT</pubDate>
      <description>&lt;p&gt;
A few years ago I needed the ability to “autolink” text – basically, I had a list
of keywords and anytime those keywords were displayed on a page I needed to have them
turned into a link. The code is relatively straightforward, but I thought it might
be of some use to other people.
&lt;/p&gt;
&lt;pre style="background-color: #f7f7f7; font-family: "&gt;&lt;font face="Consolas"&gt;&lt;span&gt;&lt;font color="#0000ff"&gt;&lt;font style="font-size: 12pt"&gt;using&lt;/font&gt;&lt;/font&gt;&lt;/span&gt;&lt;font style="font-size: 12pt"&gt; System;&lt;br /&gt;
&lt;span&gt;&lt;font color="#0000ff"&gt;using&lt;/font&gt;&lt;/span&gt; System.Collections.Generic;&lt;br /&gt;
&lt;span&gt;&lt;font color="#0000ff"&gt;using&lt;/font&gt;&lt;/span&gt; System.Linq;&lt;br /&gt;
&lt;span&gt;&lt;font color="#0000ff"&gt;using&lt;/font&gt;&lt;/span&gt; System.Text;&lt;br /&gt;
&lt;span&gt;&lt;font color="#0000ff"&gt;using&lt;/font&gt;&lt;/span&gt; System.Text.RegularExpressions;&lt;br /&gt;
&lt;br /&gt;
&lt;span&gt;&lt;font color="#0000ff"&gt;namespace&lt;/font&gt;&lt;/span&gt; RCSSolutions&lt;br /&gt;
{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;public&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#0000ff"&gt;class&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#2b91af"&gt;Term&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;public&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt; LinkTerm
{ &lt;span&gt;&lt;font color="#0000ff"&gt;get&lt;/font&gt;&lt;/span&gt;; &lt;span&gt;&lt;font color="#0000ff"&gt;set&lt;/font&gt;&lt;/span&gt;;
}&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;public&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt; Url
{ &lt;span&gt;&lt;font color="#0000ff"&gt;get&lt;/font&gt;&lt;/span&gt;; &lt;span&gt;&lt;font color="#0000ff"&gt;set&lt;/font&gt;&lt;/span&gt;;
}&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;public&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt; Target
{ &lt;span&gt;&lt;font color="#0000ff"&gt;get&lt;/font&gt;&lt;/span&gt;; &lt;span&gt;&lt;font color="#0000ff"&gt;set&lt;/font&gt;&lt;/span&gt;;
}&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; }&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;summary&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt; Adds
links to a passed in string based on records in&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt; the
SourceAutolink table.&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;/summary&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;public&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#0000ff"&gt;class&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#2b91af"&gt;AutoLinker&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; {&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;private&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt; m_linkStyle
= &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #e5e5e5"&gt;&amp;quot;&amp;quot;&lt;/font&gt;&lt;/span&gt;;&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;summary&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;List
of words which auto link&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;/summary&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;public&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#2b91af"&gt;List&lt;/font&gt;&lt;/span&gt;&amp;lt;&lt;span&gt;&lt;font color="#2b91af"&gt;Term&lt;/font&gt;&lt;/span&gt;&amp;gt;
LinkWords { &lt;span&gt;&lt;font color="#0000ff"&gt;get&lt;/font&gt;&lt;/span&gt;; &lt;span&gt;&lt;font color="#0000ff"&gt;set&lt;/font&gt;&lt;/span&gt;;
}&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;summary&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;The
CSS class to assign to the link tag&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;/summary&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;public&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt; LinkStyle&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;get&lt;/font&gt;&lt;/span&gt; { &lt;span&gt;&lt;font color="#0000ff"&gt;return&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#0000ff"&gt;this&lt;/font&gt;&lt;/span&gt;.m_linkStyle;
}&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;set&lt;/font&gt;&lt;/span&gt; { &lt;span&gt;&lt;font color="#0000ff"&gt;this&lt;/font&gt;&lt;/span&gt;.m_linkStyle
= &lt;span&gt;&lt;font color="#0000ff"&gt;value&lt;/font&gt;&lt;/span&gt;; }&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;public&lt;/font&gt;&lt;/span&gt; AutoLinker
(&lt;span&gt;&lt;font color="#2b91af"&gt;List&lt;/font&gt;&lt;/span&gt;&amp;lt;&lt;span&gt;&lt;font color="#2b91af"&gt;Term&lt;/font&gt;&lt;/span&gt;&amp;gt;
linkWords)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; LinkWords = linkWords;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;summary&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt; Adds
any links to the passed in content.&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;/summary&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;font color="#808080"&gt;&lt;span&gt;&amp;lt;param
name=&lt;/span&gt;&lt;span&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;Content
to evaluate&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;/param&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;returns&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;Marked
up results&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;/returns&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;developer&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;Paul
Mrozowski&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;/developer&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;created&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;07/07/2008&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;/created&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;public&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt; AutoLink(&lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt; content)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;if&lt;/font&gt;&lt;/span&gt; (&lt;span&gt;&lt;font color="#0000ff"&gt;this&lt;/font&gt;&lt;/span&gt;.LinkWords
== &lt;span&gt;&lt;font color="#0000ff"&gt;null&lt;/font&gt;&lt;/span&gt;)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;return&lt;/font&gt;&lt;/span&gt; content;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#2b91af"&gt;StringBuilder&lt;/font&gt;&lt;/span&gt; result
= &lt;span&gt;&lt;font color="#0000ff"&gt;new&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#2b91af"&gt;StringBuilder&lt;/font&gt;&lt;/span&gt;();&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;//
Replaces HTML (and html-like) tags with spaces (we want to keep&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;//
the same relative positions of everything else in the text since&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;//
we're going to use them to do the final replacements.)&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt; newSentence
= &lt;span&gt;&lt;font color="#2b91af"&gt;Regex&lt;/font&gt;&lt;/span&gt;.Replace(content,&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#a31515"&gt;@&amp;quot;&amp;lt;(.|\n)*?&amp;gt;&amp;quot;&lt;/font&gt;&lt;/span&gt;,&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;
match =&amp;gt; &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #e5e5e5"&gt;&amp;quot;
&amp;quot;&lt;/font&gt;&lt;/span&gt;.PadRight(match.Length));&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt; tmpContent
= content;&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;//
Loop through each link term, search for matches. Save each of them into a new collection&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;//
We're going to use the results to sort the matches in decending order by location.
That&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;//
way we can perform the replacements w/o moving the starting location of the other
replacements.&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;foreach&lt;/font&gt;&lt;/span&gt; (&lt;span&gt;&lt;font color="#0000ff"&gt;var&lt;/font&gt;&lt;/span&gt; linkRow &lt;span&gt;&lt;font color="#0000ff"&gt;in&lt;/font&gt;&lt;/span&gt; LinkWords)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;var&lt;/font&gt;&lt;/span&gt; allMatches
= &lt;span&gt;&lt;font color="#0000ff"&gt;new&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#2b91af"&gt;List&lt;/font&gt;&lt;/span&gt;&amp;lt;&lt;span&gt;&lt;font color="#2b91af"&gt;Match&lt;/font&gt;&lt;/span&gt;&amp;gt;();&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#2b91af"&gt;MatchCollection&lt;/font&gt;&lt;/span&gt; matches
= &lt;span&gt;&lt;font color="#2b91af"&gt;Regex&lt;/font&gt;&lt;/span&gt;.Matches(newSentence, linkRow.LinkTerm, &lt;span&gt;&lt;font color="#2b91af"&gt;RegexOptions&lt;/font&gt;&lt;/span&gt;.IgnoreCase);&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;foreach&lt;/font&gt;&lt;/span&gt; (&lt;span&gt;&lt;font color="#2b91af"&gt;Match&lt;/font&gt;&lt;/span&gt; match &lt;span&gt;&lt;font color="#0000ff"&gt;in&lt;/font&gt;&lt;/span&gt; matches)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;
allMatches.Add(match);&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;var&lt;/font&gt;&lt;/span&gt; orderedMatches
= &lt;span&gt;&lt;font color="#0000ff"&gt;from&lt;/font&gt;&lt;/span&gt; m &lt;span&gt;&lt;font color="#0000ff"&gt;in&lt;/font&gt;&lt;/span&gt; allMatches&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;orderby&lt;/font&gt;&lt;/span&gt; m.Index &lt;span&gt;&lt;font color="#0000ff"&gt;descending&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;select&lt;/font&gt;&lt;/span&gt; m;&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;//
General idea is to grab all of the text following the match, get the newly&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;//
link word w/html markup and insert it before the this text. Then truncate&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;//
the original content to remove everything from the starting position of the&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;//
match to the end of file - this is basically done so I don't have to track&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;//
the current position within the file. After we're done with the loop we&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;//
insert anything that's left to the beginning of the new string.&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;foreach&lt;/font&gt;&lt;/span&gt; (&lt;span&gt;&lt;font color="#2b91af"&gt;Match&lt;/font&gt;&lt;/span&gt; item &lt;span&gt;&lt;font color="#0000ff"&gt;in&lt;/font&gt;&lt;/span&gt; orderedMatches)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;
{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt; endOfMatchedStringToEOF
= tmpContent.Substring(item.Index + item.Length);&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;
result.Insert(0, GetAutolinkText(linkRow, item.Value) + endOfMatchedStringToEOF);&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;
tmpContent = tmpContent.Substring(0, item.Index);&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;
}&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; result.Insert(0,
tmpContent);&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;return&lt;/font&gt;&lt;/span&gt; result.ToString();&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;summary&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt; Get
the replacement text.&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;/summary&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;font color="#808080"&gt;&lt;span&gt;&amp;lt;param
name=&lt;/span&gt;&lt;span&gt;&amp;quot;token&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;Word
token&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;/param&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;font color="#808080"&gt;&lt;span&gt;&amp;lt;param
name=&lt;/span&gt;&lt;span&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;Original
content&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;/param&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;returns&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;Empty
string if no replacement&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;/returns&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;developer&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;Paul
Mrozowski&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;/developer&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#808080"&gt;///&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;&amp;#160;&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;created&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;07/08/2008&lt;/font&gt;&lt;/span&gt;&lt;span&gt;&lt;font color="#808080"&gt;&amp;lt;/created&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;private&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt; GetAutolinkText(&lt;span&gt;&lt;font color="#2b91af"&gt;Term&lt;/font&gt;&lt;/span&gt; linkTo, &lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt; match)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt; newWord
= match;&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;if&lt;/font&gt;&lt;/span&gt; (&lt;span&gt;&lt;font color="#0000ff"&gt;this&lt;/font&gt;&lt;/span&gt;.m_linkStyle.Length
== 0)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;
newWord = &lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt;.Format(&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #e5e5e5"&gt;&amp;quot;&amp;lt;a
href='{0}' &amp;quot;&lt;/font&gt;&lt;/span&gt;, linkTo.Url);&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;else&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;
newWord = &lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt;.Format(&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #e5e5e5"&gt;&amp;quot;&amp;lt;a
class='{0}' href='{1}' &amp;quot;&lt;/font&gt;&lt;/span&gt;, 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;this&lt;/font&gt;&lt;/span&gt;.LinkStyle, 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;
linkTo.Url);&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;if&lt;/font&gt;&lt;/span&gt; ((linkTo.Target
?? &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #e5e5e5"&gt;&amp;quot;&amp;quot;&lt;/font&gt;&lt;/span&gt;).Length
&amp;gt; 0)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;
newWord += &lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt;.Format(&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #e5e5e5"&gt;&amp;quot;target='{0}'
&amp;quot;&lt;/font&gt;&lt;/span&gt;, linkTo.Target);&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #ffffbf"&gt;//
We pass in the original match term to maintain its case (the initial match was case-insensitive).&lt;/font&gt;&lt;/span&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; newWord += &lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt;.Format(&lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #e5e5e5"&gt;&amp;quot;&amp;gt;{0}&amp;lt;/a&amp;gt;&amp;quot;&lt;/font&gt;&lt;/span&gt;,
match);&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;return&lt;/font&gt;&lt;/span&gt; newWord;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; }&lt;br /&gt;
}&lt;/font&gt;&lt;/font&gt;
&lt;br /&gt;
&lt;/pre&gt;
&lt;p&gt;
Usage is simple – create a list of terms that you want linked (along with the URL,
style (if any), and target) and pass it to the AutoLinker class, then call AutoLink
with your source text. It will return the text with the links embedded in it. Here’s
a sample from a console application:
&lt;/p&gt;
&lt;pre&gt;&lt;font face="Consolas"&gt;&lt;font style="font-size: 12pt"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;static&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#0000ff"&gt;void&lt;/font&gt;&lt;/span&gt; Main(&lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt;[]
args)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;var&lt;/font&gt;&lt;/span&gt; terms
= &lt;span&gt;&lt;font color="#0000ff"&gt;new&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#2b91af"&gt;List&lt;/font&gt;&lt;/span&gt;&amp;lt;&lt;span&gt;&lt;font color="#2b91af"&gt;Term&lt;/font&gt;&lt;/span&gt;&amp;gt;();&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; terms.Add(&lt;span&gt;&lt;font color="#0000ff"&gt;new&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#2b91af"&gt;Term&lt;/font&gt;&lt;/span&gt;()
{ LinkTerm = &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #e5e5e5"&gt;&amp;quot;Hello&amp;quot;&lt;/font&gt;&lt;/span&gt;,
Target = &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #e5e5e5"&gt;&amp;quot;_blank&amp;quot;&lt;/font&gt;&lt;/span&gt;,
Url = &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #e5e5e5"&gt;&amp;quot;http://www.rcs-solutions.com&amp;quot;&lt;/font&gt;&lt;/span&gt; });&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;string&lt;/font&gt;&lt;/span&gt; sentence
= &lt;span style="background-image: none; background-attachment: scroll; background-repeat: repeat; background-position: 0% 0%"&gt;&lt;font style="background-color: #e5e5e5"&gt;&amp;quot;Why,
hello! This is a sentence where I'm going to link to the word \&amp;quot;hello\&amp;quot;.&amp;quot;&lt;/font&gt;&lt;/span&gt;;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#2b91af"&gt;Console&lt;/font&gt;&lt;/span&gt;.Write(sentence);&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#0000ff"&gt;var&lt;/font&gt;&lt;/span&gt; linker
= &lt;span&gt;&lt;font color="#0000ff"&gt;new&lt;/font&gt;&lt;/span&gt;&amp;#160;&lt;span&gt;&lt;font color="#2b91af"&gt;AutoLinker&lt;/font&gt;&lt;/span&gt;(terms);&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#2b91af"&gt;Console&lt;/font&gt;&lt;/span&gt;.Write(linker.AutoLink(sentence));&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span&gt;&lt;font color="#2b91af"&gt;Console&lt;/font&gt;&lt;/span&gt;.ReadKey();&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&lt;/font&gt;&lt;/font&gt;&lt;/pre&gt;
&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=c3498c80-09ad-42a8-a4e0-6e7f03caceb0" /&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,c3498c80-09ad-42a8-a4e0-6e7f03caceb0.aspx</comments>
      <category>.NET</category>
    </item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=c914191d-95fd-4d88-bcbb-11bb6b89761f</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,c914191d-95fd-4d88-bcbb-11bb6b89761f.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,c914191d-95fd-4d88-bcbb-11bb6b89761f.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c914191d-95fd-4d88-bcbb-11bb6b89761f</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Interfaces are an integral part of .NET, yet a lot of new .NET developers (especially
those coming from weakly-typed languages, or languages where interfaces aren't supported)
have difficulty in understanding why they're needed and how (and when) they're used.
If you find yourself in that group you're in good company. It's not a difficult concept
but it can be a bit foreign to developers new to them. 
</p>
        <p>
Let's get the textbook definition out of the way, then take a look at what it really
means (and why you should even care). From Wikipedia: 
</p>
        <p>
"Interface generally refers to an abstraction that an entity provides of itself
to the outside. This separates the methods of external communication from internal
operation, and allows it to be internally modified without affecting the way outside
entities interact with it, as well as provide multiple abstractions of itself. It
may also provide a means of translation between entities which do not speak the same
language, such as between a human and a computer." 
</p>
        <p>
Hmm - OK. While technically correct that doesn't really help, does it? Did your eyes
glaze over like mine did while reading that? Maybe if we back up a bit and look at
what a class is we might be able to make some sense of this. 
</p>
        <h3>The Basics
</h3>
        <p>
A class is a collection of methods, properties, and events. It is assumed that each
of these methods, properties, and events "do something". At least in most
cases (we're going to ignore the idea of an abstract class for right now). So far,
so good. You can create a new instance of this class and do things with it, pass it
around to other classes as a parameter, etc. In a weakly typed language (also known
as a "dynamic language") you can pretty much pass any type of class around
without having to worry about the type - as long as your code doesn't try to access
a property or method that object doesn't have, you're good to go. The upside to this
is that it's pretty flexible. The downside to this is that mistakes aren't caught
at compile time - your app. just blows up at runtime (so you'd better test!). Strongly-typed
languages take a different approach: you must define the types that can be passed
as parameters to methods. That's OK as long as there is only one specific type your
method acts on, or the type you're passing in inherits from the base type of the parameter
- it's pretty straightforward. The upside is that mistakes (like trying to access
a property or method that doesn't exist) is caught at compile time. The downside is
that it's not as flexible as a dynamic language. 
</p>
        <p>
So what do I mean by "not as flexible"? On the surface it seems pretty reasonable
that a strongly-typed method only accepts specific types - how else would the compiler
(and you) know that it's safe to access a specific method or property? It doesn't.
It only can accept that specific type of class, or any subclass of that same type. 
</p>
        <p>
Why is it OK to accept a subclass of the type? Well, the compiler can be sure that
the subclass has the same exact properties &amp; methods as its parent (it doesn't
care if you add more of them or override the behavior). 
</p>
        <p>
But what if it doesn't? What if you had a class that wasn't of the correct type necssary
to pass into a method and it didn't inherit from that type either? Let's take a look
at an example of this. I wanted to keep it simple enough to understand, but have it
be a REAL scenario (not some contrived example). Those goals are a bit difficult to
balance so I error'd on the real scenario side of things. Hopefully it'll help you
understand WHY some things are the way they are in the framework in addition to understanding
interfaces. 
</p>
        <h3>A Real Example
</h3>
        <p>
For example, let's suppose we create a collection class that can have a collection
of objects (that are all of the same type) and we want to have a method which can
sort them. You want to write a generic Sort routine on your collection class that
can sort any kind of collection of objects, as long as they're the same type. The
first issue you'd run into is, "How do I generically create some code which can
compare ANY type?" Remember - you have to be able to compare strings, numbers,
date/times, maybe custom types someone may have created, etc. So it's not really possible
to be able to compare ANY type. You could cover the basic types and then require the
user to subclass your collection for any other custom types. It's a bit clunky, but
it would work. 
</p>
        <p>
What if, instead, we decided that we'd have another class responsible for doing the
sorting. We'd provide a default implementation and if you had your own custom types
that needed to be sorted you could pass in your own implementation. That's a bit better.
The developer would still need to subclass from our default implementation (since
we've still got the strongly-typed issues here - again, dynamic languages don't have
this "issue"). We could have the developer pass in their version of the
class which does the comparison into the Sort() method. The passed in class would
have a Compare() method and let's say it takes two parameters of the types of the
same type of object and returns an integer value indicating whether one of the objects
is less than, greater than, or equal to the other. 
</p>
        <p>
Let's take a look at what the code might look like for all of this: 
</p>
        <div style="border-bottom: #000080 1px solid; border-left: #000080 1px solid; font-family: 'Courier New', courier, monospace; color: #000; font-size: 10pt; border-top: #000080 1px solid; border-right: #000080 1px solid">
          <div style="padding-bottom: 2px; background-color: #dfdfdf; padding-left: 5px; padding-right: 5px; max-height: 400px; overflow: auto; padding-top: 2px">
            <span style="color: #0000ff">public</span>
            <span style="color: #0000ff">class</span>
            <span style="color: #2b91af">Comparer</span>
            <br />
{ 
<br />
    <span style="color: #0000ff">public</span><span style="color: #0000ff">int</span> Compare(<span style="color: #0000ff">object</span> x, <span style="color: #0000ff">object</span> y) 
<br />
    { 
<br />
        <span style="background: #ffffbf">// Code
to do comparisons here </span><br />
    } 
<br />
} 
<br /><br /><span style="color: #0000ff">public</span><span style="color: #0000ff">class</span><span style="color: #2b91af">SampleArrayList</span><br />
{ 
<br />
    <span style="color: #0000ff">public</span><span style="color: #0000ff">virtual</span><span style="color: #0000ff">void</span> Sort() 
<br />
    { 
<br />
        <span style="color: #0000ff">this</span>.Sort(<span style="color: #0000ff">new</span><span style="color: #2b91af">Comparer</span>()); 
<br />
    } 
<br /><br />
    <span style="color: #0000ff">public</span><span style="color: #0000ff">virtual</span><span style="color: #0000ff">void</span> Sort(<span style="color: #2b91af">Comparer</span> comparer) 
<br />
    { 
<br />
        <span style="background: #ffffbf">// Do
sorting here. Call out to comparer object to do the actual comparison </span><br />
    } 
<br />
}
</div>
        </div>
        <p>
 
</p>
        <div style="border-bottom: #000080 1px solid; border-left: #000080 1px solid; font-family: 'Courier New', courier, monospace; color: #000; font-size: 10pt; border-top: #000080 1px solid; border-right: #000080 1px solid">
          <div style="padding-bottom: 2px; background-color: #dfdfdf; padding-left: 5px; padding-right: 5px; max-height: 300px; overflow: auto; padding-top: 2px">
            <span style="color: #2b91af">SampleArrayList</span> list
= <span style="color: #0000ff">new</span><span style="color: #2b91af">SampleArrayList</span>(); 
<br /><span style="background: #ffffbf">// Add items to the list </span><br />
list.Sort(); <span style="background: #ffffbf">// default implementation </span><br />
list.Sort(<span style="color: #0000ff">new</span> SomeComparerSubclass()); <span style="background: #ffffbf">//
A custom sort </span></div>
        </div>
        <p>
          <br />
That looks OK. If I wanted to create my own comparison class all I'd do is subclass
from Comparer and override Compare() with my own implementation. But let's take a
step back and think about this for a bit. If you create a new class and want a method
that can compare one instance of that class to another instance of it, where's the
best place for the code? Doing comparison's is a pretty fundamental capability of
a class - we do it all the time with string's, numbers, datetimes, etc. so clearly
it belongs with the class, right? Your only other alternative would be to put it into
another class that acts as a kind of "helper". That's effectively what we've
forced on any developers that want to use the sorting capability of our collection
for their own custom classes. They MUST create a helper class to do a comparison or
they'd all have to inherit from our Comparer class (and use it as their base object).
That might not be the end of the world but we're only talking about a single example
- there are a lot of other places where this scenario comes up. 
<br /><br />
OK, having to create another class which only does a comparison for a specific type
isn't all that great. Since it makes more sense to have a comparison handled by the
object being compared, let's say we add a method called CompareTo() to any class when
we want to be able to compare it against another instance. In our Comparer class we'll
call that method and, hey, our comparer class is now a bit more generic right? We
know that in .NET all objects inherit from "System.Object" so having our
Comparer class's Compare() method accept "objects" means we can use it with
ANY type. I don't actually have to create a new class for each and every item I'm
going to compare! But wait - we're STILL going to have the problem with calling the
CompareTo() method on our class in the collection; we're back to having to inherit
from a common base class.
</p>
        <p>
 
</p>
        <div style="border-bottom: #000080 1px solid; border-left: #000080 1px solid; font-family: 'Courier New', courier, monospace; color: #000; font-size: 10pt; border-top: #000080 1px solid; border-right: #000080 1px solid">
          <div style="padding-bottom: 2px; background-color: #dfdfdf; padding-left: 5px; padding-right: 5px; max-height: 300px; overflow: auto; padding-top: 2px">
            <span style="color: #0000ff">public</span>
            <span style="color: #0000ff">class</span>
            <span style="color: #2b91af">Comparer</span>
            <br />
{ 
<br />
    <span style="color: #0000ff">public</span><span style="color: #0000ff">int</span> Compare(<span style="color: #0000ff">object</span> x, <span style="color: #0000ff">object</span> y) 
<br />
    { 
<br />
        <span style="background: #ffffbf">// Code
to do comparisons here </span><br />
        <span style="color: #0000ff">return</span> x.CompareTo(y.CompareTo()); 
<br />
    } 
<br />
}
</div>
        </div>
        <br />
But now how can we call the CompareTo() method on those objects? How do we even know
if those objects have a CompareTo() method? Since .NET is strongly typed you can't
do this - it won't even compile. The class type "object" doesn't have a
"CompareTo" method. The .NET compiler knows that and it won't let you do
that. 
<br /><br />
This is begining to feel like a circular issue, isn't it? 
<p></p><h3>Breaking the Cycle
</h3><p>
OK, now what? Well, you could jump through a lot of hoops and use reflection to make
the method call for you. But it's a lot of work. In a dynamic language (such as Visual
FoxPro) code like that is perfectly valid - I can pass any object type into a method
like that and access any properties or methods and VFP doesn't care. If the object
doesn't have those properties or methods it will just blow up at runtime. I'm a good
developer so I won't pass in something that would blow up. .NET sucks - it makes things
so difficult. 
</p><p>
You're basically stuck at this point - you can't do what you'd like to do in .NET.
If .NET supported the idea of multiple inheritance (where class C could inherit from
Class A and from Class B at the same time), we'd be able to still make this work.
But it doesn't. 
</p><h3>Interfaces to the Rescue
</h3><p>
That's where interfaces come in (finally!). Let's take another stab at a more concrete
definition of an interface: An Interface is a definition of the types of properties,
events, and methods a class needs to implement. It's nothing more than a list of properties,
events, and methods (and the various types associated with them) that a class has
to have. While we can't inherit from multiple classes in .NET, we can inherit from
multiple interfaces. 
</p><p>
Getting back to our example, we could define an interface that consists of a public
method called CompareTo that accepts one parameter of the "System.Object"
type ("object" for short). This method needs to return an integer: Less
than zero means this instance is less than the object passed in, zero means it's equal,
and greater than one means it's greater than the passed in object. 
</p><p>
Here's what it might look like: 
</p><div style="border-bottom: #000080 1px solid; border-left: #000080 1px solid; font-family: 'Courier New', courier, monospace; color: #000; font-size: 10pt; border-top: #000080 1px solid; border-right: #000080 1px solid"><div style="padding-bottom: 2px; background-color: #dfdfdf; padding-left: 5px; padding-right: 5px; max-height: 300px; overflow: auto; padding-top: 2px"><span style="color: #0000ff">public</span><span style="color: #0000ff">interface</span><span style="color: #2b91af">IComparable</span><br />
{ 
<br />
    <span style="color: #0000ff">int</span> CompareTo(<span style="color: #0000ff">object</span> obj); 
<br />
}
</div></div><p>
While we're at it, it seems like we might want to do something similar to our Comparer
class: 
</p><div style="border-bottom: #000080 1px solid; border-left: #000080 1px solid; font-family: 'Courier New', courier, monospace; color: #000; font-size: 10pt; border-top: #000080 1px solid; border-right: #000080 1px solid"><div style="padding-bottom: 2px; background-color: #dfdfdf; padding-left: 5px; padding-right: 5px; max-height: 300px; overflow: auto; padding-top: 2px"><span style="color: #0000ff">public</span><span style="color: #0000ff">interface</span><span style="color: #2b91af">IComparer</span><br />
{ 
<br />
   <span style="color: #0000ff">int</span> Compare(<span style="color: #0000ff">object</span> x, <span style="color: #0000ff">object</span> y); 
<br />
}
</div></div><br /><br />
Now all we'd need to do is make sure that any class that we want to compare inherits
from the IComparer interface and then "implements" the specified properties,
methods, and events (PEM). That is, you need to make sure your class has all of the
same PEM's as the interface. Then you use the interface as the parameter type instead.
Since we can inherit multiple interfaces on a given type we have a way of giving our
classes the cameleon-like ability of appearing as exactly the right type to methods,
regardless of what class it really inherits from. We'd do the same thing for any class
which can compare two different classes. 
<br /><br />
So we can rewrite the above code: 
<p></p><div style="border-bottom: #000080 1px solid; border-left: #000080 1px solid; font-family: 'Courier New', courier, monospace; color: #000; font-size: 10pt; border-top: #000080 1px solid; border-right: #000080 1px solid"><div style="padding-bottom: 2px; background-color: #dfdfdf; padding-left: 5px; padding-right: 5px; max-height: 300px; overflow: auto; padding-top: 2px"><span style="color: #0000ff">public</span><span style="color: #0000ff">class</span><span style="color: #2b91af">Comparer</span> : <span style="color: #2b91af">IComparer</span><br />
{ 
<br />
   <span style="color: #0000ff">public</span><span style="color: #0000ff">int</span> Compare(<span style="color: #0000ff">object</span> x, <span style="color: #0000ff">object</span> y) 
<br />
   { 
<br />
       <span style="background: #ffffbf">// Code here
which compares x to y and returns integer </span><br />
   } 
<br />
} 
<br /><br /><span style="color: #0000ff">public</span><span style="color: #0000ff">class</span><span style="color: #2b91af">MyCustomClass</span> : <span style="color: #2b91af">IComparable</span><br />
{ 
<br />
   <span style="color: #0000ff">public</span><span style="color: #0000ff">int</span> CompareTo(<span style="color: #0000ff">object</span> obj) 
<br />
   { 
<br />
   } 
<br />
   <span style="color: #0000ff">public</span><span style="color: #0000ff">int</span> CompareTo(<span style="color: #2b91af">MyCustomClass</span> obj) 
<br />
   { 
<br />
   } 
<br />
}
</div></div><p><br />
And we rewrite the Sort() method on our collection class SampleArrayList to accept
objects of type "IComparer" instead of "Comparer":  
<br /></p><div style="border-bottom: #000080 1px solid; border-left: #000080 1px solid; font-family: 'Courier New', courier, monospace; color: #000; font-size: 10pt; border-top: #000080 1px solid; border-right: #000080 1px solid"><div style="padding-bottom: 2px; background-color: #dfdfdf; padding-left: 5px; padding-right: 5px; max-height: 300px; overflow: auto; padding-top: 2px"><span style="color: #0000ff">public</span><span style="color: #0000ff">void</span> Sort(<span style="color: #2b91af">IComparer</span> comparer) 
<br />
{ 
<br />
   <span style="background: #ffffbf">// Code here that iterates over the
collection and class Compare() </span><br />
   <span style="background: #ffffbf">// with two of the items in our internal
list. </span><br /><span style="background: #ffffbf">}</span></div></div><br /><br />
Suddenly all of this starts working again - you get compiler-time checking to make
sure things don't blow up, Intellisense works, etc. In fact the compiler verifies
that you have, in fact, done all of this correctly - if your classes don't implement
IComparer or IComparable it will let you know. You have the ability to create a custom
class that compares objects in different ways (which makes it easy to come up with
different ways of sorting, ex. ascending, descending) and have generic code which
will work in most cases. 
<p></p><h3>Conclusion
</h3><p>
The scenario I described above plays out throughout the .NET framework. Fundamental
things like garbage collection are handled via the IDisposable interface, iterating
over a collection (think foreach) is handled by IEnumerable, comparing objects (like
we described above) is handled by IComparer and IComparable. Interfaces are used extensively.
Hopefully you've gotten a feel for why they're needed and how they're used inside
of .NET. 
</p><p><em>Originally published in Universal Thread Magazine, April 2009</em></p><img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=c914191d-95fd-4d88-bcbb-11bb6b89761f" /></body>
      <title>What&amp;rsquo;s an Interface and Why Should I Care?</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,c914191d-95fd-4d88-bcbb-11bb6b89761f.aspx</guid>
      <link>http://www.rcs-solutions.com/blog/2010/07/15/WhatrsquosAnInterfaceAndWhyShouldICare.aspx</link>
      <pubDate>Thu, 15 Jul 2010 23:00:42 GMT</pubDate>
      <description>&lt;p&gt;
Interfaces are an integral part of .NET, yet a lot of new .NET developers (especially
those coming from weakly-typed languages, or languages where interfaces aren't supported)
have difficulty in understanding why they're needed and how (and when) they're used.
If you find yourself in that group you're in good company. It's not a difficult concept
but it can be a bit foreign to developers new to them. 
&lt;/p&gt;
&lt;p&gt;
Let's get the textbook definition out of the way, then take a look at what it really
means (and why you should even care). From Wikipedia: 
&lt;/p&gt;
&lt;p&gt;
&amp;quot;Interface generally refers to an abstraction that an entity provides of itself
to the outside. This separates the methods of external communication from internal
operation, and allows it to be internally modified without affecting the way outside
entities interact with it, as well as provide multiple abstractions of itself. It
may also provide a means of translation between entities which do not speak the same
language, such as between a human and a computer.&amp;quot; 
&lt;/p&gt;
&lt;p&gt;
Hmm - OK. While technically correct that doesn't really help, does it? Did your eyes
glaze over like mine did while reading that? Maybe if we back up a bit and look at
what a class is we might be able to make some sense of this. 
&lt;/p&gt;
&lt;h3&gt;The Basics
&lt;/h3&gt;
&lt;p&gt;
A class is a collection of methods, properties, and events. It is assumed that each
of these methods, properties, and events &amp;quot;do something&amp;quot;. At least in most
cases (we're going to ignore the idea of an abstract class for right now). So far,
so good. You can create a new instance of this class and do things with it, pass it
around to other classes as a parameter, etc. In a weakly typed language (also known
as a &amp;quot;dynamic language&amp;quot;) you can pretty much pass any type of class around
without having to worry about the type - as long as your code doesn't try to access
a property or method that object doesn't have, you're good to go. The upside to this
is that it's pretty flexible. The downside to this is that mistakes aren't caught
at compile time - your app. just blows up at runtime (so you'd better test!). Strongly-typed
languages take a different approach: you must define the types that can be passed
as parameters to methods. That's OK as long as there is only one specific type your
method acts on, or the type you're passing in inherits from the base type of the parameter
- it's pretty straightforward. The upside is that mistakes (like trying to access
a property or method that doesn't exist) is caught at compile time. The downside is
that it's not as flexible as a dynamic language. 
&lt;/p&gt;
&lt;p&gt;
So what do I mean by &amp;quot;not as flexible&amp;quot;? On the surface it seems pretty reasonable
that a strongly-typed method only accepts specific types - how else would the compiler
(and you) know that it's safe to access a specific method or property? It doesn't.
It only can accept that specific type of class, or any subclass of that same type. 
&lt;/p&gt;
&lt;p&gt;
Why is it OK to accept a subclass of the type? Well, the compiler can be sure that
the subclass has the same exact properties &amp;amp; methods as its parent (it doesn't
care if you add more of them or override the behavior). 
&lt;/p&gt;
&lt;p&gt;
But what if it doesn't? What if you had a class that wasn't of the correct type necssary
to pass into a method and it didn't inherit from that type either? Let's take a look
at an example of this. I wanted to keep it simple enough to understand, but have it
be a REAL scenario (not some contrived example). Those goals are a bit difficult to
balance so I error'd on the real scenario side of things. Hopefully it'll help you
understand WHY some things are the way they are in the framework in addition to understanding
interfaces. 
&lt;/p&gt;
&lt;h3&gt;A Real Example
&lt;/h3&gt;
&lt;p&gt;
For example, let's suppose we create a collection class that can have a collection
of objects (that are all of the same type) and we want to have a method which can
sort them. You want to write a generic Sort routine on your collection class that
can sort any kind of collection of objects, as long as they're the same type. The
first issue you'd run into is, &amp;quot;How do I generically create some code which can
compare ANY type?&amp;quot; Remember - you have to be able to compare strings, numbers,
date/times, maybe custom types someone may have created, etc. So it's not really possible
to be able to compare ANY type. You could cover the basic types and then require the
user to subclass your collection for any other custom types. It's a bit clunky, but
it would work. 
&lt;/p&gt;
&lt;p&gt;
What if, instead, we decided that we'd have another class responsible for doing the
sorting. We'd provide a default implementation and if you had your own custom types
that needed to be sorted you could pass in your own implementation. That's a bit better.
The developer would still need to subclass from our default implementation (since
we've still got the strongly-typed issues here - again, dynamic languages don't have
this &amp;quot;issue&amp;quot;). We could have the developer pass in their version of the
class which does the comparison into the Sort() method. The passed in class would
have a Compare() method and let's say it takes two parameters of the types of the
same type of object and returns an integer value indicating whether one of the objects
is less than, greater than, or equal to the other. 
&lt;/p&gt;
&lt;p&gt;
Let's take a look at what the code might look like for all of this: 
&lt;/p&gt;
&lt;div style="border-bottom: #000080 1px solid; border-left: #000080 1px solid; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; color: #000; font-size: 10pt; border-top: #000080 1px solid; border-right: #000080 1px solid"&gt;
&lt;div style="padding-bottom: 2px; background-color: #dfdfdf; padding-left: 5px; padding-right: 5px; max-height: 400px; overflow: auto; padding-top: 2px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Comparer&lt;/span&gt; 
&lt;br /&gt;
{ 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Compare(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; x, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; y) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background: #ffffbf"&gt;// Code
to do comparisons here &lt;/span&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; } 
&lt;br /&gt;
} 
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af"&gt;SampleArrayList&lt;/span&gt; 
&lt;br /&gt;
{ 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;virtual&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Sort() 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Sort(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Comparer&lt;/span&gt;()); 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; } 
&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;virtual&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Sort(&lt;span style="color: #2b91af"&gt;Comparer&lt;/span&gt; comparer) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background: #ffffbf"&gt;// Do
sorting here. Call out to comparer object to do the actual comparison &lt;/span&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; } 
&lt;br /&gt;
}
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;div style="border-bottom: #000080 1px solid; border-left: #000080 1px solid; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; color: #000; font-size: 10pt; border-top: #000080 1px solid; border-right: #000080 1px solid"&gt;
&lt;div style="padding-bottom: 2px; background-color: #dfdfdf; padding-left: 5px; padding-right: 5px; max-height: 300px; overflow: auto; padding-top: 2px"&gt;&lt;span style="color: #2b91af"&gt;SampleArrayList&lt;/span&gt; list
= &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;SampleArrayList&lt;/span&gt;(); 
&lt;br /&gt;
&lt;span style="background: #ffffbf"&gt;// Add items to the list &lt;/span&gt; 
&lt;br /&gt;
list.Sort(); &lt;span style="background: #ffffbf"&gt;// default implementation &lt;/span&gt; 
&lt;br /&gt;
list.Sort(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SomeComparerSubclass()); &lt;span style="background: #ffffbf"&gt;//
A custom sort &lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;br /&gt;
That looks OK. If I wanted to create my own comparison class all I'd do is subclass
from Comparer and override Compare() with my own implementation. But let's take a
step back and think about this for a bit. If you create a new class and want a method
that can compare one instance of that class to another instance of it, where's the
best place for the code? Doing comparison's is a pretty fundamental capability of
a class - we do it all the time with string's, numbers, datetimes, etc. so clearly
it belongs with the class, right? Your only other alternative would be to put it into
another class that acts as a kind of &amp;quot;helper&amp;quot;. That's effectively what we've
forced on any developers that want to use the sorting capability of our collection
for their own custom classes. They MUST create a helper class to do a comparison or
they'd all have to inherit from our Comparer class (and use it as their base object).
That might not be the end of the world but we're only talking about a single example
- there are a lot of other places where this scenario comes up. 
&lt;br /&gt;
&lt;br /&gt;
OK, having to create another class which only does a comparison for a specific type
isn't all that great. Since it makes more sense to have a comparison handled by the
object being compared, let's say we add a method called CompareTo() to any class when
we want to be able to compare it against another instance. In our Comparer class we'll
call that method and, hey, our comparer class is now a bit more generic right? We
know that in .NET all objects inherit from &amp;quot;System.Object&amp;quot; so having our
Comparer class's Compare() method accept &amp;quot;objects&amp;quot; means we can use it with
ANY type. I don't actually have to create a new class for each and every item I'm
going to compare! But wait - we're STILL going to have the problem with calling the
CompareTo() method on our class in the collection; we're back to having to inherit
from a common base class.
&lt;/p&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;div style="border-bottom: #000080 1px solid; border-left: #000080 1px solid; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; color: #000; font-size: 10pt; border-top: #000080 1px solid; border-right: #000080 1px solid"&gt;
&lt;div style="padding-bottom: 2px; background-color: #dfdfdf; padding-left: 5px; padding-right: 5px; max-height: 300px; overflow: auto; padding-top: 2px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Comparer&lt;/span&gt; 
&lt;br /&gt;
{ 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Compare(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; x, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; y) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background: #ffffbf"&gt;// Code
to do comparisons here &lt;/span&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; x.CompareTo(y.CompareTo()); 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; } 
&lt;br /&gt;
}
&lt;/div&gt;
&lt;/div&gt;
&lt;br /&gt;
But now how can we call the CompareTo() method on those objects? How do we even know
if those objects have a CompareTo() method? Since .NET is strongly typed you can't
do this - it won't even compile. The class type &amp;quot;object&amp;quot; doesn't have a
&amp;quot;CompareTo&amp;quot; method. The .NET compiler knows that and it won't let you do
that. 
&lt;br /&gt;
&lt;br /&gt;
This is begining to feel like a circular issue, isn't it? 
&lt;p&gt;
&lt;/p&gt;
&lt;h3&gt;Breaking the Cycle
&lt;/h3&gt;
&lt;p&gt;
OK, now what? Well, you could jump through a lot of hoops and use reflection to make
the method call for you. But it's a lot of work. In a dynamic language (such as Visual
FoxPro) code like that is perfectly valid - I can pass any object type into a method
like that and access any properties or methods and VFP doesn't care. If the object
doesn't have those properties or methods it will just blow up at runtime. I'm a good
developer so I won't pass in something that would blow up. .NET sucks - it makes things
so difficult. 
&lt;/p&gt;
&lt;p&gt;
You're basically stuck at this point - you can't do what you'd like to do in .NET.
If .NET supported the idea of multiple inheritance (where class C could inherit from
Class A and from Class B at the same time), we'd be able to still make this work.
But it doesn't. 
&lt;/p&gt;
&lt;h3&gt;Interfaces to the Rescue
&lt;/h3&gt;
&lt;p&gt;
That's where interfaces come in (finally!). Let's take another stab at a more concrete
definition of an interface: An Interface is a definition of the types of properties,
events, and methods a class needs to implement. It's nothing more than a list of properties,
events, and methods (and the various types associated with them) that a class has
to have. While we can't inherit from multiple classes in .NET, we can inherit from
multiple interfaces. 
&lt;/p&gt;
&lt;p&gt;
Getting back to our example, we could define an interface that consists of a public
method called CompareTo that accepts one parameter of the &amp;quot;System.Object&amp;quot;
type (&amp;quot;object&amp;quot; for short). This method needs to return an integer: Less
than zero means this instance is less than the object passed in, zero means it's equal,
and greater than one means it's greater than the passed in object. 
&lt;/p&gt;
&lt;p&gt;
Here's what it might look like: 
&lt;/p&gt;
&lt;div style="border-bottom: #000080 1px solid; border-left: #000080 1px solid; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; color: #000; font-size: 10pt; border-top: #000080 1px solid; border-right: #000080 1px solid"&gt;
&lt;div style="padding-bottom: 2px; background-color: #dfdfdf; padding-left: 5px; padding-right: 5px; max-height: 300px; overflow: auto; padding-top: 2px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; &lt;span style="color: #2b91af"&gt;IComparable&lt;/span&gt; 
&lt;br /&gt;
{ 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; CompareTo(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; obj); 
&lt;br /&gt;
}
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
While we're at it, it seems like we might want to do something similar to our Comparer
class: 
&lt;/p&gt;
&lt;div style="border-bottom: #000080 1px solid; border-left: #000080 1px solid; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; color: #000; font-size: 10pt; border-top: #000080 1px solid; border-right: #000080 1px solid"&gt;
&lt;div style="padding-bottom: 2px; background-color: #dfdfdf; padding-left: 5px; padding-right: 5px; max-height: 300px; overflow: auto; padding-top: 2px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; &lt;span style="color: #2b91af"&gt;IComparer&lt;/span&gt; 
&lt;br /&gt;
{ 
&lt;br /&gt;
&amp;#160;&amp;#160; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Compare(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; x, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; y); 
&lt;br /&gt;
}
&lt;/div&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Now all we'd need to do is make sure that any class that we want to compare inherits
from the IComparer interface and then &amp;quot;implements&amp;quot; the specified properties,
methods, and events (PEM). That is, you need to make sure your class has all of the
same PEM's as the interface. Then you use the interface as the parameter type instead.
Since we can inherit multiple interfaces on a given type we have a way of giving our
classes the cameleon-like ability of appearing as exactly the right type to methods,
regardless of what class it really inherits from. We'd do the same thing for any class
which can compare two different classes. 
&lt;br /&gt;
&lt;br /&gt;
So we can rewrite the above code: 
&lt;p&gt;
&lt;/p&gt;
&lt;div style="border-bottom: #000080 1px solid; border-left: #000080 1px solid; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; color: #000; font-size: 10pt; border-top: #000080 1px solid; border-right: #000080 1px solid"&gt;
&lt;div style="padding-bottom: 2px; background-color: #dfdfdf; padding-left: 5px; padding-right: 5px; max-height: 300px; overflow: auto; padding-top: 2px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Comparer&lt;/span&gt; : &lt;span style="color: #2b91af"&gt;IComparer&lt;/span&gt; 
&lt;br /&gt;
{ 
&lt;br /&gt;
&amp;#160;&amp;#160; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Compare(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; x, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt; y) 
&lt;br /&gt;
&amp;#160;&amp;#160; { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="background: #ffffbf"&gt;// Code here
which compares x to y and returns integer &lt;/span&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160; } 
&lt;br /&gt;
} 
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af"&gt;MyCustomClass&lt;/span&gt; : &lt;span style="color: #2b91af"&gt;IComparable&lt;/span&gt; 
&lt;br /&gt;
{ 
&lt;br /&gt;
&amp;#160;&amp;#160; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; CompareTo(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; obj) 
&lt;br /&gt;
&amp;#160;&amp;#160; { 
&lt;br /&gt;
&amp;#160;&amp;#160; } 
&lt;br /&gt;
&amp;#160;&amp;#160; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; CompareTo(&lt;span style="color: #2b91af"&gt;MyCustomClass&lt;/span&gt; obj) 
&lt;br /&gt;
&amp;#160;&amp;#160; { 
&lt;br /&gt;
&amp;#160;&amp;#160; } 
&lt;br /&gt;
}
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;br /&gt;
And we rewrite the Sort() method on our collection class SampleArrayList to accept
objects of type &amp;quot;IComparer&amp;quot; instead of &amp;quot;Comparer&amp;quot;:&amp;#160; 
&lt;br /&gt;
&lt;/p&gt;
&lt;div style="border-bottom: #000080 1px solid; border-left: #000080 1px solid; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; color: #000; font-size: 10pt; border-top: #000080 1px solid; border-right: #000080 1px solid"&gt;
&lt;div style="padding-bottom: 2px; background-color: #dfdfdf; padding-left: 5px; padding-right: 5px; max-height: 300px; overflow: auto; padding-top: 2px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Sort(&lt;span style="color: #2b91af"&gt;IComparer&lt;/span&gt; comparer) 
&lt;br /&gt;
{ 
&lt;br /&gt;
&amp;#160;&amp;#160; &lt;span style="background: #ffffbf"&gt;// Code here that iterates over the
collection and class Compare() &lt;/span&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160; &lt;span style="background: #ffffbf"&gt;// with two of the items in our internal
list. &lt;/span&gt; 
&lt;br /&gt;
&lt;span style="background: #ffffbf"&gt;}&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Suddenly all of this starts working again - you get compiler-time checking to make
sure things don't blow up, Intellisense works, etc. In fact the compiler verifies
that you have, in fact, done all of this correctly - if your classes don't implement
IComparer or IComparable it will let you know. You have the ability to create a custom
class that compares objects in different ways (which makes it easy to come up with
different ways of sorting, ex. ascending, descending) and have generic code which
will work in most cases. 
&lt;p&gt;
&lt;/p&gt;
&lt;h3&gt;Conclusion
&lt;/h3&gt;
&lt;p&gt;
The scenario I described above plays out throughout the .NET framework. Fundamental
things like garbage collection are handled via the IDisposable interface, iterating
over a collection (think foreach) is handled by IEnumerable, comparing objects (like
we described above) is handled by IComparer and IComparable. Interfaces are used extensively.
Hopefully you've gotten a feel for why they're needed and how they're used inside
of .NET. 
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;Originally published in Universal Thread Magazine, April 2009&lt;/em&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=c914191d-95fd-4d88-bcbb-11bb6b89761f" /&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,c914191d-95fd-4d88-bcbb-11bb6b89761f.aspx</comments>
      <category>.NET</category>
      <category>C#</category>
    </item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=781a324d-b708-40da-b759-235f9f3cc5f7</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,781a324d-b708-40da-b759-235f9f3cc5f7.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,781a324d-b708-40da-b759-235f9f3cc5f7.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=781a324d-b708-40da-b759-235f9f3cc5f7</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I've been working on a server monitoring Windows service recently - it's meant to
keep an eye on our servers for various types of failures and, if possible, automatically
recover from them. One of the failures our website experiences once in a while has
to do with our forums. I integrated a third party forum package into our site so our
stores have a place to post messages and talk with one another. Occasionally (and
I have yet to reproduce the failure steps) it will fail, complaining that it can't
find some configuration file. The quick fix is to reset IIS; usually I'll just remote
into the server and do an IISRESET from the command prompt. I wanted my service to
keep an eye out for this type of failure and automatically recycle IIS. Long term
I'd love to track down this failure and fix it the proper way but in the meantime
I just want to be able to recover gracefully.
</p>
        <p>
I found the ServiceController class after a bit of digging and wrapped it up into
two static methods I could call to reset IIS. I just had to figure out the name of
the service I needed to refer to. The easiest way I found of finding this was to just
cycle through the services and display their names. You could write a quick console
app. to do this, but I just used <a href="http://www.linqpad.net" target="_blank">LINQPad</a>,
switched it to C# Statements, added a reference to the System.ServiceProcess.dll (hit
F4), then added the namespace System.ServiceProcess and ran the code. 
</p>
        <p>
As an aside: I can't say enough nice things about LINQPad - it makes it so nice to
be able to test out new classes and ideas. Its name would lead you to believe it's
only good for testing LINQ queries, but you can test out almost any .NET code you
want. I spent the whopping $19 to upgrade to the full version, which adds Intellisense
(the free version doesn't include that). I've added LINQPad to my "must have" .NET
toolkit.
</p>
        <p>
          <img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="image" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/StartingandStoppingServicesin.NET_12E87/image_3.png" width="826" height="666" />
        </p>
        <p>
You might be wondering what the Dump() method does, since it's not part of the ServiceController
class. LINQPad has a nice extension method named Dump() that makes it trivial to dump
out the response from almost anything. My sample doesn't show it, but it even handles
nested classes nicely. OK, enough fawning...
</p>
        <p>
I ran this code which made it really easy to find the service names I was interested
in. Once I had them I wrapped up a few of the services I wanted to be able to cycle
in their own methods. I ended up wrapping the Start/Stop calls in a try/catch; it
would throw an exception if I tried starting a service which was already running or
stopping a service which had already stopped. 
</p>
        <div style="font-family: consolas, courier new; background: white; color: black; font-size: 10pt">
          <p style="margin: 0px">
            <span style="color: blue">private</span>
            <span style="color: blue">void</span> ResetIIS()
</p>
          <p style="margin: 0px">
{
</p>
          <p style="margin: 0px">
    StopService(<span style="background: #e5e5e5">"W3SVC"</span>, 10);
</p>
          <p style="margin: 0px">
    StartService(<span style="background: #e5e5e5">"W3SVC"</span>,
15);
</p>
          <p style="margin: 0px">
}
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
            <span style="color: blue">private</span>
            <span style="color: blue">void</span> ResetStateServer()
</p>
          <p style="margin: 0px">
{
</p>
          <p style="margin: 0px">
    StopService(<span style="background: #e5e5e5">"aspnet_state"</span>,
15);
</p>
          <p style="margin: 0px">
    StartService(<span style="background: #e5e5e5">"aspnet_state"</span>,
15);
</p>
          <p style="margin: 0px">
}
</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> StopService(<span style="color: blue">string</span> serviceName, <span style="color: blue">int</span> timeoutSeconds)
</p>
          <p style="margin: 0px">
{
</p>
          <p style="margin: 0px">
    <span style="color: blue">using</span> (<span style="color: #2b91af">ServiceController</span> controller
= <span style="color: blue">new</span><span style="color: #2b91af">ServiceController</span>(serviceName))
</p>
          <p style="margin: 0px">
    {
</p>
          <p style="margin: 0px">
        <span style="color: blue">try</span></p>
          <p style="margin: 0px">
        {
</p>
          <p style="margin: 0px">
            controller.Stop();
</p>
          <p style="margin: 0px">
            controller.WaitForStatus(<span style="color: #2b91af">ServiceControllerStatus</span>.Stopped, <span style="color: #2b91af">TimeSpan</span>.FromSeconds(timeoutSeconds));
</p>
          <p style="margin: 0px">
        }
</p>
          <p style="margin: 0px">
        <span style="color: blue">catch</span> (<span style="color: #2b91af">InvalidOperationException</span> ex)
</p>
          <p style="margin: 0px">
        {
</p>
          <p style="margin: 0px">
            <span style="background: #ffffbf">//
Service may already be stopped</span></p>
          <p style="margin: 0px">
        }
</p>
          <p style="margin: 0px">
    }            
</p>
          <p style="margin: 0px">
}
</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> StartService(<span style="color: blue">string</span> serviceName, <span style="color: blue">int</span> timeoutSeconds)
</p>
          <p style="margin: 0px">
{
</p>
          <p style="margin: 0px">
    <span style="color: blue">using</span> (<span style="color: #2b91af">ServiceController</span> controller
= <span style="color: blue">new</span><span style="color: #2b91af">ServiceController</span>(serviceName))
</p>
          <p style="margin: 0px">
    {
</p>
          <p style="margin: 0px">
        <span style="color: blue">try</span></p>
          <p style="margin: 0px">
        {
</p>
          <p style="margin: 0px">
            controller.Start();
</p>
          <p style="margin: 0px">
            controller.WaitForStatus(<span style="color: #2b91af">ServiceControllerStatus</span>.Running, <span style="color: #2b91af">TimeSpan</span>.FromSeconds(timeoutSeconds));
</p>
          <p style="margin: 0px">
        }
</p>
          <p style="margin: 0px">
        <span style="color: blue">catch</span> (<span style="color: #2b91af">InvalidOperationException</span> ex)
</p>
          <p style="margin: 0px">
        {
</p>
          <p style="margin: 0px">
            <span style="background: #ffffbf">//
Service may already be running</span></p>
          <p style="margin: 0px">
        }    
</p>
          <p style="margin: 0px">
    }            
</p>
          <p style="margin: 0px">
}
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
            <span style="color: blue">private</span>
            <span style="color: blue">void</span> ListServices()
</p>
          <p style="margin: 0px">
{
</p>
          <p style="margin: 0px">
    <span style="color: #2b91af">ServiceController</span>[] services
= <span style="color: #2b91af">ServiceController</span>.GetServices();
</p>
          <p style="margin: 0px">
    <span style="color: blue">foreach</span> (<span style="color: #2b91af">ServiceController</span> service <span style="color: blue">in</span> services)
</p>
          <p style="margin: 0px">
    {
</p>
          <p style="margin: 0px">
        <span style="color: blue">string</span> name
= service.DisplayName + <span style="background: #e5e5e5">" : "</span> + service.ServiceName;
</p>
          <p style="margin: 0px">
        <span style="color: #2b91af">Console</span>.WriteLine(name);
</p>
          <p style="margin: 0px">
        <span style="background: #ffffbf">//name.Dump();</span></p>
          <p style="margin: 0px">
    }
</p>
          <p style="margin: 0px">
}
</p>
        </div>
        <p>
          <br />
          <b>Links:</b>
        </p>
        <p>
          <a href="http://www.linqpad.net">http://www.linqpad.net</a>
        </p>
        <img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=781a324d-b708-40da-b759-235f9f3cc5f7" />
      </body>
      <title>Starting and Stopping Services in .NET</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,781a324d-b708-40da-b759-235f9f3cc5f7.aspx</guid>
      <link>http://www.rcs-solutions.com/blog/2009/07/26/StartingAndStoppingServicesInNET.aspx</link>
      <pubDate>Sun, 26 Jul 2009 01:30:50 GMT</pubDate>
      <description>&lt;p&gt;
I've been working on a server monitoring Windows service recently - it's meant to
keep an eye on our servers for various types of failures and, if possible, automatically
recover from them. One of the failures our website experiences once in a while has
to do with our forums. I integrated a third party forum package into our site so our
stores have a place to post messages and talk with one another. Occasionally (and
I have yet to reproduce the failure steps) it will fail, complaining that it can't
find some configuration file. The quick fix is to reset IIS; usually I'll just remote
into the server and do an IISRESET from the command prompt. I wanted my service to
keep an eye out for this type of failure and automatically recycle IIS. Long term
I'd love to track down this failure and fix it the proper way but in the meantime
I just want to be able to recover gracefully.
&lt;/p&gt;
&lt;p&gt;
I found the ServiceController class after a bit of digging and wrapped it up into
two static methods I could call to reset IIS. I just had to figure out the name of
the service I needed to refer to. The easiest way I found of finding this was to just
cycle through the services and display their names. You could write a quick console
app. to do this, but I just used &lt;a href="http://www.linqpad.net" target="_blank"&gt;LINQPad&lt;/a&gt;,
switched it to C# Statements, added a reference to the System.ServiceProcess.dll (hit
F4), then added the namespace System.ServiceProcess and ran the code. 
&lt;/p&gt;
&lt;p&gt;
As an aside: I can't say enough nice things about LINQPad - it makes it so nice to
be able to test out new classes and ideas. Its name would lead you to believe it's
only good for testing LINQ queries, but you can test out almost any .NET code you
want. I spent the whopping $19 to upgrade to the full version, which adds Intellisense
(the free version doesn't include that). I've added LINQPad to my "must have" .NET
toolkit.
&lt;/p&gt;
&lt;p&gt;
&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="image" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/StartingandStoppingServicesin.NET_12E87/image_3.png" width="826" height="666"&gt; 
&lt;/p&gt;
&lt;p&gt;
You might be wondering what the Dump() method does, since it's not part of the ServiceController
class. LINQPad has a nice extension method named Dump() that makes it trivial to dump
out the response from almost anything. My sample doesn't show it, but it even handles
nested classes nicely. OK, enough fawning...
&lt;/p&gt;
&lt;p&gt;
I ran this code which made it really easy to find the service names I was interested
in. Once I had them I wrapped up a few of the services I wanted to be able to cycle
in their own methods. I ended up wrapping the Start/Stop calls in a try/catch; it
would throw an exception if I tried starting a service which was already running or
stopping a service which had already stopped. 
&lt;/p&gt;
&lt;div style="font-family: consolas, courier new; background: white; color: black; font-size: 10pt"&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; ResetIIS()
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; StopService(&lt;span style="background: #e5e5e5"&gt;"W3SVC"&lt;/span&gt;, 10);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; StartService(&lt;span style="background: #e5e5e5"&gt;"W3SVC"&lt;/span&gt;,
15);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; ResetStateServer()
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; StopService(&lt;span style="background: #e5e5e5"&gt;"aspnet_state"&lt;/span&gt;,
15);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; StartService(&lt;span style="background: #e5e5e5"&gt;"aspnet_state"&lt;/span&gt;,
15);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&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; StopService(&lt;span style="color: blue"&gt;string&lt;/span&gt; serviceName, &lt;span style="color: blue"&gt;int&lt;/span&gt; timeoutSeconds)
&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;using&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;ServiceController&lt;/span&gt; controller
= &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;ServiceController&lt;/span&gt;(serviceName))
&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;&amp;nbsp; &lt;span style="color: blue"&gt;try&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; {
&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; controller.Stop();
&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; controller.WaitForStatus(&lt;span style="color: #2b91af"&gt;ServiceControllerStatus&lt;/span&gt;.Stopped, &lt;span style="color: #2b91af"&gt;TimeSpan&lt;/span&gt;.FromSeconds(timeoutSeconds));
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&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; &lt;span style="color: blue"&gt;catch&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;InvalidOperationException&lt;/span&gt; ex)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&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; &lt;span style="background: #ffffbf"&gt;//
Service may already be stopped&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; }
&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; 
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&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; StartService(&lt;span style="color: blue"&gt;string&lt;/span&gt; serviceName, &lt;span style="color: blue"&gt;int&lt;/span&gt; timeoutSeconds)
&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;using&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;ServiceController&lt;/span&gt; controller
= &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;ServiceController&lt;/span&gt;(serviceName))
&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;&amp;nbsp; &lt;span style="color: blue"&gt;try&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; {
&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; controller.Start();
&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; controller.WaitForStatus(&lt;span style="color: #2b91af"&gt;ServiceControllerStatus&lt;/span&gt;.Running, &lt;span style="color: #2b91af"&gt;TimeSpan&lt;/span&gt;.FromSeconds(timeoutSeconds));
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&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; &lt;span style="color: blue"&gt;catch&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;InvalidOperationException&lt;/span&gt; ex)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&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; &lt;span style="background: #ffffbf"&gt;//
Service may already be running&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; 
&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; 
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; ListServices()
&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: #2b91af"&gt;ServiceController&lt;/span&gt;[] services
= &lt;span style="color: #2b91af"&gt;ServiceController&lt;/span&gt;.GetServices();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;foreach&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;ServiceController&lt;/span&gt; service &lt;span style="color: blue"&gt;in&lt;/span&gt; services)
&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;&amp;nbsp; &lt;span style="color: blue"&gt;string&lt;/span&gt; name
= service.DisplayName + &lt;span style="background: #e5e5e5"&gt;" : "&lt;/span&gt; + service.ServiceName;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(name);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="background: #ffffbf"&gt;//name.Dump();&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;/p&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;br&gt;
&lt;b&gt;Links:&lt;/b&gt; 
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.linqpad.net"&gt;http://www.linqpad.net&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=781a324d-b708-40da-b759-235f9f3cc5f7" /&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,781a324d-b708-40da-b759-235f9f3cc5f7.aspx</comments>
      <category>.NET</category>
      <category>C#</category>
    </item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=f0ffb32b-b0e0-434c-895c-71a384f20799</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,f0ffb32b-b0e0-434c-895c-71a384f20799.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,f0ffb32b-b0e0-434c-895c-71a384f20799.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=f0ffb32b-b0e0-434c-895c-71a384f20799</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Check out my article in this month's <a href="http://www.universalthread.com/ViewPageMainPage.aspx?Session=37395863654242725751383D204A2F4E456275325279766563597439693271307250673D3D" target="_blank">UT
Magazine (April 2009)</a> about interfaces in .NET. I try to explain the how's and
why's of them, especially when coming from a loosely-typed language (such as VFP).
Hopefully you'll find it useful.
</p>
        <img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=f0ffb32b-b0e0-434c-895c-71a384f20799" />
      </body>
      <title>What's an Interface?</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,f0ffb32b-b0e0-434c-895c-71a384f20799.aspx</guid>
      <link>http://www.rcs-solutions.com/blog/2009/04/21/WhatsAnInterface.aspx</link>
      <pubDate>Tue, 21 Apr 2009 22:38:58 GMT</pubDate>
      <description>&lt;p&gt;
Check out my article in this month's &lt;a href="http://www.universalthread.com/ViewPageMainPage.aspx?Session=37395863654242725751383D204A2F4E456275325279766563597439693271307250673D3D" target="_blank"&gt;UT
Magazine (April 2009)&lt;/a&gt; about interfaces in .NET. I try to explain the how's and
why's of them, especially when coming from a loosely-typed language (such as VFP).
Hopefully you'll find it useful.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=f0ffb32b-b0e0-434c-895c-71a384f20799" /&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,f0ffb32b-b0e0-434c-895c-71a384f20799.aspx</comments>
      <category>.NET</category>
    </item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=32a4ffa4-0389-4b6c-94a3-3f637f5cac89</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,32a4ffa4-0389-4b6c-94a3-3f637f5cac89.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,32a4ffa4-0389-4b6c-94a3-3f637f5cac89.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=32a4ffa4-0389-4b6c-94a3-3f637f5cac89</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <style type="text/css">
.code { background-color: #efefef; font-family:consolas,courier new; }
</style>
Extension methods were added as a new compiler feature in .NET 3.5. More specifically,
that means you can use VS 2008 to use an extension method and then use VS's multi-targeting
to run it under .NET 2.0. They're basically a means of tacking on methods onto existing
classes or interfaces w/o actually needed to subclass or modify an interface. It's
used extensively by (and added because of) LINQ. The methods aren't really part of
the class, but the way you use them (and the way they appear in intellisense) make
them feel like they're now part of the class. They're essentially static methods scoped
to a specific interface or class. 
</p>
        <p>
I've been playing around with them a bit and ran into a case where I thought they'd
be kind of a cool fit. I've needed to be able to convert a datatable into a comma-delimited
file (CSV) so it can easily be opening in something like Excel, or pretty much anything
that understands CSV files. I could create a separate class to do this, but it seems
like this should be part of the DataTable class. To write an extension method you
basically create a static method in a static class and prefix the first parameter
with "this". Yep, that's about it. 
</p>
        <p>
I wanted it to basically work like this: 
</p>
        <div class="code">DataTable table = myBizObj.DataSet.Tables["SomeTable"]; 
<br />
string csv = table.ToCSV(); 
</div>
        <p>
Creating the CSV is pretty straightforward - I loop through the column headers to
generate the first header row, then I loop through each row in the table, then each
item in the ItemArray of the row. I specifically decided to use quotes as delimiters
around everything to keep it simple - the rules as to when you can/should include
quotes for a CSV are pretty complicated. The only thing I do is escape out embedded
quotes in the data by doubling them, ex. " becomes "". As soon as I had it working,
I decided to create a few more overloads to let me control whether a header row was
required, and the actual delimiter used (ex. instead of comma you could change it
to a | pipe for example). Their is some example code in the XML help at the top of
the class. In addition, I'm actually using this for a web page so it might be helpful
to see what that code looks like: 
</p>
        <div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new">
          <p style="margin: 0px">
            <span style="color: blue">string</span> results = act.DataSet.Tables[tableName].ToCSV();
</p>
          <p style="margin: 0px">
            <span style="color: blue">string</span> mimeType = RCSSolutions.Web.<span style="color: #2b91af">Utility</span>.DetermineMimeType(<span style="background: #e5e5e5">"csv"</span>);
</p>
          <p style="margin: 0px">
Response.ContentType = mimeType;
</p>
          <p style="margin: 0px">
Response.AddHeader(<span style="background: #e5e5e5">"Content-Length"</span>, results.Length.ToString());
</p>
          <p style="margin: 0px">
Response.AddHeader(<span style="background: #e5e5e5">"Content-disposition"</span>,
</p>
          <p style="margin: 0px">
                  
s<span style="color: blue">tring</span>.Format(<span style="background: #e5e5e5">"attachment;filename={0}"</span>, <span style="background: #e5e5e5">"DelimitedList.CSV"</span>));
</p>
          <p style="margin: 0px">
Response.Write(results);
</p>
          <p style="margin: 0px">
Response.End();
</p>
        </div>
        <p>
I'm calling out to another helper class which returns the mime type - in this case,
all it does is return "application/csv". The above code basically pops open a dialog
box with the file name filled in the browser on the client side. 
</p>
        <div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new">
          <p style="margin: 0px">
            <span style="color: blue">using</span> System;
</p>
          <p style="margin: 0px">
            <span style="color: blue">using</span> System.Collections.Generic;
</p>
          <p style="margin: 0px">
            <span style="color: blue">using</span> System.Data;
</p>
          <p style="margin: 0px">
            <span style="color: blue">using</span> System.Linq;
</p>
          <p style="margin: 0px">
            <span style="color: blue">using</span> System.Text;
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
            <span style="color: blue">namespace</span> RCSSolutions.Utility
</p>
          <p style="margin: 0px">
{
</p>
          <p style="margin: 0px">
    <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;summary&gt;</span></p>
          <p style="margin: 0px">
    <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;para&gt;</span><span style="background: #ffffbf">Various
extension methods.</span><span style="color: gray">&lt;/para&gt;</span></p>
          <p style="margin: 0px">
    <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;/summary&gt;</span></p>
          <p style="margin: 0px">
    <span style="color: gray">///</span><span style="background: #ffffbf"> Sample
of using ToCSV</span></p>
          <p style="margin: 0px">
    <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;example&gt;</span></p>
          <p style="margin: 0px">
    <span style="color: gray">///</span><span style="background: #ffffbf"> DataTable
table = dv.Table;</span></p>
          <p style="margin: 0px">
    <span style="color: gray">///</span><span style="background: #ffffbf"> //
Assumes table is a DataTable</span></p>
          <p style="margin: 0px">
    <span style="color: gray">///</span><span style="background: #ffffbf"> string
result = table.ToCSV(true);</span></p>
          <p style="margin: 0px">
    <span style="color: gray">///</span><span style="background: #ffffbf"> System.IO.File.WriteAllText(@"C:\sample.csv",
result);</span></p>
          <p style="margin: 0px">
    <span style="color: gray">///</span><span style="background: #ffffbf"> System.Diagnostics.Process
proc = new System.Diagnostics.Process();</span></p>
          <p style="margin: 0px">
    <span style="color: gray">///</span><span style="background: #ffffbf"> proc.StartInfo.FileName
= @"C:\sample.csv";</span></p>
          <p style="margin: 0px">
    <span style="color: gray">///</span><span style="background: #ffffbf"> proc.StartInfo.UseShellExecute
= true;</span></p>
          <p style="margin: 0px">
    <span style="color: gray">///</span><span style="background: #ffffbf"> proc.Start();</span></p>
          <p style="margin: 0px">
    <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;/example&gt;</span></p>
          <p style="margin: 0px">
    <span style="color: blue">public</span><span style="color: blue">static</span><span style="color: blue">class</span><span style="color: #2b91af">Extensions</span></p>
          <p style="margin: 0px">
    {        
</p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;summary&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"> Converts
the passed in data table to a CSV-style string.       </span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;/summary&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;param
name="table"&gt;</span><span style="background: #ffffbf">Table to convert</span><span style="color: gray">&lt;/param&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;returns&gt;</span><span style="background: #ffffbf">Resulting
CSV-style string</span><span style="color: gray">&lt;/returns&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: blue">public</span><span style="color: blue">static</span><span style="color: blue">string</span> ToCSV(<span style="color: blue">this</span><span style="color: #2b91af">DataTable</span> table)
</p>
          <p style="margin: 0px">
        {
</p>
          <p style="margin: 0px">
            <span style="color: blue">return</span> ToCSV(table, <span style="background: #e5e5e5">","</span>, <span style="color: blue">true</span>);
</p>
          <p style="margin: 0px">
        }
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;summary&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"> Converts
the passed in data table to a CSV-style string.</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;/summary&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;param
name="table"&gt;</span><span style="background: #ffffbf">Table to convert</span><span style="color: gray">&lt;/param&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;param
name="includeHeader"&gt;</span><span style="background: #ffffbf">true - include headers</span><span style="color: gray">&lt;br/&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"> false
- do not include header column</span><span style="color: gray">&lt;/param&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;returns&gt;</span><span style="background: #ffffbf">Resulting
CSV-style string</span><span style="color: gray">&lt;/returns&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: blue">public</span><span style="color: blue">static</span><span style="color: blue">string</span> ToCSV(<span style="color: blue">this</span><span style="color: #2b91af">DataTable</span> table, <span style="color: blue">bool</span> includeHeader)
</p>
          <p style="margin: 0px">
        {
</p>
          <p style="margin: 0px">
            <span style="color: blue">return</span> ToCSV(table, <span style="background: #e5e5e5">","</span>,
includeHeader);
</p>
          <p style="margin: 0px">
        }
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;summary&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"> Converts
the passed in data table to a CSV-style string.</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;/summary&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;param
name="table"&gt;</span><span style="background: #ffffbf">Table to convert</span><span style="color: gray">&lt;/param&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;param
name="delimiter"&gt;</span><span style="background: #ffffbf">Delimiter used to separate
fields</span><span style="color: gray">&lt;/param&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;param
name="includeHeader"&gt;</span><span style="background: #ffffbf">true - include headers</span><span style="color: gray">&lt;br/&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"> false
- do not include header column</span><span style="color: gray">&lt;/param&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: gray">///</span><span style="background: #ffffbf"></span><span style="color: gray">&lt;returns&gt;</span><span style="background: #ffffbf">Resulting
CSV-style string</span><span style="color: gray">&lt;/returns&gt;</span></p>
          <p style="margin: 0px">
        <span style="color: blue">public</span><span style="color: blue">static</span><span style="color: blue">string</span> ToCSV(<span style="color: blue">this</span><span style="color: #2b91af">DataTable</span> table, <span style="color: blue">string</span> delimiter, <span style="color: blue">bool</span> includeHeader)
</p>
          <p style="margin: 0px">
        {
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">StringBuilder</span> result
= <span style="color: blue">new</span><span style="color: #2b91af">StringBuilder</span>();
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
            <span style="color: blue">if</span> (includeHeader)
</p>
          <p style="margin: 0px">
            {
</p>
          <p style="margin: 0px">
                <span style="color: blue">foreach</span> (<span style="color: #2b91af">DataColumn</span> column <span style="color: blue">in</span> table.Columns)
</p>
          <p style="margin: 0px">
               
{
</p>
          <p style="margin: 0px">
                   
result.Append(column.ColumnName);
</p>
          <p style="margin: 0px">
                   
result.Append(delimiter);
</p>
          <p style="margin: 0px">
               
}
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
               
result.Remove(--result.Length, 0);
</p>
          <p style="margin: 0px">
               
result.Append(<span style="color: #2b91af">Environment</span>.NewLine);
</p>
          <p style="margin: 0px">
            }
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
            <span style="color: blue">foreach</span> (<span style="color: #2b91af">DataRow</span> row <span style="color: blue">in</span> table.Rows)
</p>
          <p style="margin: 0px">
            {
</p>
          <p style="margin: 0px">
                <span style="color: blue">foreach</span> (<span style="color: blue">object</span> item <span style="color: blue">in</span> row.ItemArray)
</p>
          <p style="margin: 0px">
               
{
</p>
          <p style="margin: 0px">
                    <span style="color: blue">if</span> (item <span style="color: blue">is</span> System.<span style="color: #2b91af">DBNull</span>)
</p>
          <p style="margin: 0px">
                       
result.Append(delimiter);
</p>
          <p style="margin: 0px">
                    <span style="color: blue">else</span></p>
          <p style="margin: 0px">
                   
{
</p>
          <p style="margin: 0px">
                        <span style="color: blue">string</span> itemAsString
= item.ToString();
</p>
          <p style="margin: 0px">
                        <span style="background: #ffffbf">//
Double up all embedded double quotes</span></p>
          <p style="margin: 0px">
                       
itemAsString = itemAsString.Replace(<span style="background: #e5e5e5">"\""</span>, <span style="background: #e5e5e5">"\"\""</span>);
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
                        <span style="background: #ffffbf">//
To keep things simple, always delimit with double-quotes</span></p>
          <p style="margin: 0px">
                        <span style="background: #ffffbf">//
so we don't have to determine in which cases they're necessary</span></p>
          <p style="margin: 0px">
                        <span style="background: #ffffbf">//
and which cases they're not.</span></p>
          <p style="margin: 0px">
                       
itemAsString = <span style="background: #e5e5e5">"\""</span> + itemAsString + <span style="background: #e5e5e5">"\""</span>;
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
                       
result.Append(itemAsString + delimiter);
</p>
          <p style="margin: 0px">
                   
}
</p>
          <p style="margin: 0px">
               
}
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
               
result.Remove(--result.Length, 0);
</p>
          <p style="margin: 0px">
               
result.Append(<span style="color: #2b91af">Environment</span>.NewLine);
</p>
          <p style="margin: 0px">
            }
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
            <span style="color: blue">return</span> result.ToString();
</p>
          <p style="margin: 0px">
        }
</p>
          <p style="margin: 0px">
    }
</p>
          <p style="margin: 0px">
}
</p>
        </div>
        <img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=32a4ffa4-0389-4b6c-94a3-3f637f5cac89" />
      </body>
      <title>Convert DataTable to CSV via Extension Method</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,32a4ffa4-0389-4b6c-94a3-3f637f5cac89.aspx</guid>
      <link>http://www.rcs-solutions.com/blog/2009/01/15/ConvertDataTableToCSVViaExtensionMethod.aspx</link>
      <pubDate>Thu, 15 Jan 2009 01:57:00 GMT</pubDate>
      <description>&lt;p&gt;
&lt;style type="text/css"&gt;
.code { background-color: #efefef; font-family:consolas,courier new; }
&lt;/style&gt;
Extension methods were added as a new compiler feature in .NET 3.5. More specifically,
that means you can use VS 2008 to use an extension method and then use VS's multi-targeting
to run it under .NET 2.0. They're basically a means of tacking on methods onto existing
classes or interfaces w/o actually needed to subclass or modify an interface. It's
used extensively by (and added because of) LINQ. The methods aren't really part of
the class, but the way you use them (and the way they appear in intellisense) make
them feel like they're now part of the class. They're essentially static methods scoped
to a specific interface or class. 
&lt;/p&gt;
&lt;p&gt;
I've been playing around with them a bit and ran into a case where I thought they'd
be kind of a cool fit. I've needed to be able to convert a datatable into a comma-delimited
file (CSV) so it can easily be opening in something like Excel, or pretty much anything
that understands CSV files. I could create a separate class to do this, but it seems
like this should be part of the DataTable class. To write an extension method you
basically create a static method in a static class and prefix the first parameter
with "this". Yep, that's about it. 
&lt;/p&gt;
&lt;p&gt;
I wanted it to basically work like this: 
&lt;/p&gt;
&lt;div class="code"&gt;DataTable table = myBizObj.DataSet.Tables["SomeTable"]; 
&lt;br&gt;
string csv = table.ToCSV(); 
&lt;/div&gt;
&lt;p&gt;
Creating the CSV is pretty straightforward - I loop through the column headers to
generate the first header row, then I loop through each row in the table, then each
item in the ItemArray of the row. I specifically decided to use quotes as delimiters
around everything to keep it simple - the rules as to when you can/should include
quotes for a CSV are pretty complicated. The only thing I do is escape out embedded
quotes in the data by doubling them, ex. " becomes "". As soon as I had it working,
I decided to create a few more overloads to let me control whether a header row was
required, and the actual delimiter used (ex. instead of comma you could change it
to a | pipe for example). Their is some example code in the XML help at the top of
the class. In addition, I'm actually using this for a web page so it might be helpful
to see what that code looks like: 
&lt;/p&gt;
&lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;string&lt;/span&gt; results = act.DataSet.Tables[tableName].ToCSV();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;string&lt;/span&gt; mimeType = RCSSolutions.Web.&lt;span style="color: #2b91af"&gt;Utility&lt;/span&gt;.DetermineMimeType(&lt;span style="background: #e5e5e5"&gt;"csv"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
Response.ContentType = mimeType;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
Response.AddHeader(&lt;span style="background: #e5e5e5"&gt;"Content-Length"&lt;/span&gt;, results.Length.ToString());
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
Response.AddHeader(&lt;span style="background: #e5e5e5"&gt;"Content-disposition"&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;
s&lt;span style="color: blue"&gt;tring&lt;/span&gt;.Format(&lt;span style="background: #e5e5e5"&gt;"attachment;filename={0}"&lt;/span&gt;, &lt;span style="background: #e5e5e5"&gt;"DelimitedList.CSV"&lt;/span&gt;));
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
Response.Write(results);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
Response.End();
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
I'm calling out to another helper class which returns the mime type - in this case,
all it does is return "application/csv". The above code basically pops open a dialog
box with the file name filled in the browser on the client side. 
&lt;/p&gt;
&lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;using&lt;/span&gt; System;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;using&lt;/span&gt; System.Data;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;using&lt;/span&gt; System.Linq;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;using&lt;/span&gt; System.Text;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;namespace&lt;/span&gt; RCSSolutions.Utility
&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: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;para&amp;gt;&lt;/span&gt;&lt;span style="background: #ffffbf"&gt;Various
extension methods.&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/para&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; Sample
of using ToCSV&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;example&amp;gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; DataTable
table = dv.Table;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; //
Assumes table is a DataTable&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; string
result = table.ToCSV(true);&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; System.IO.File.WriteAllText(@"C:\sample.csv",
result);&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; System.Diagnostics.Process
proc = new System.Diagnostics.Process();&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; proc.StartInfo.FileName
= @"C:\sample.csv";&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; proc.StartInfo.UseShellExecute
= true;&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; proc.Start();&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/example&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;public&lt;/span&gt; &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;Extensions&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; 
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;summary&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;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; Converts
the passed in data table to a CSV-style string.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &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; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/summary&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;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;param
name="table"&amp;gt;&lt;/span&gt;&lt;span style="background: #ffffbf"&gt;Table to convert&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&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;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style="background: #ffffbf"&gt;Resulting
CSV-style string&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/returns&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;&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;string&lt;/span&gt; ToCSV(&lt;span style="color: blue"&gt;this&lt;/span&gt; &lt;span style="color: #2b91af"&gt;DataTable&lt;/span&gt; table)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&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; &lt;span style="color: blue"&gt;return&lt;/span&gt; ToCSV(table, &lt;span style="background: #e5e5e5"&gt;","&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;&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; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;summary&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;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; Converts
the passed in data table to a CSV-style 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; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/summary&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;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;param
name="table"&amp;gt;&lt;/span&gt;&lt;span style="background: #ffffbf"&gt;Table to convert&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&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;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;param
name="includeHeader"&amp;gt;&lt;/span&gt;&lt;span style="background: #ffffbf"&gt;true - include headers&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;br/&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;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; false
- do not include header column&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&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;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style="background: #ffffbf"&gt;Resulting
CSV-style string&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/returns&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;&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;string&lt;/span&gt; ToCSV(&lt;span style="color: blue"&gt;this&lt;/span&gt; &lt;span style="color: #2b91af"&gt;DataTable&lt;/span&gt; table, &lt;span style="color: blue"&gt;bool&lt;/span&gt; includeHeader)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&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; &lt;span style="color: blue"&gt;return&lt;/span&gt; ToCSV(table, &lt;span style="background: #e5e5e5"&gt;","&lt;/span&gt;,
includeHeader);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&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; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;summary&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;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; Converts
the passed in data table to a CSV-style 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; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/summary&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;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;param
name="table"&amp;gt;&lt;/span&gt;&lt;span style="background: #ffffbf"&gt;Table to convert&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&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;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;param
name="delimiter"&amp;gt;&lt;/span&gt;&lt;span style="background: #ffffbf"&gt;Delimiter used to separate
fields&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&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;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;param
name="includeHeader"&amp;gt;&lt;/span&gt;&lt;span style="background: #ffffbf"&gt;true - include headers&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;br/&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;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; false
- do not include header column&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/param&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;&amp;nbsp; &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; &lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style="background: #ffffbf"&gt;Resulting
CSV-style string&lt;/span&gt;&lt;span style="color: gray"&gt;&amp;lt;/returns&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;&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;string&lt;/span&gt; ToCSV(&lt;span style="color: blue"&gt;this&lt;/span&gt; &lt;span style="color: #2b91af"&gt;DataTable&lt;/span&gt; table, &lt;span style="color: blue"&gt;string&lt;/span&gt; delimiter, &lt;span style="color: blue"&gt;bool&lt;/span&gt; includeHeader)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&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; &lt;span style="color: #2b91af"&gt;StringBuilder&lt;/span&gt; result
= &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;StringBuilder&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; &lt;span style="color: blue"&gt;if&lt;/span&gt; (includeHeader)
&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; {
&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: #2b91af"&gt;DataColumn&lt;/span&gt; column &lt;span style="color: blue"&gt;in&lt;/span&gt; table.Columns)
&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;&amp;nbsp;
result.Append(column.ColumnName);
&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;
result.Append(delimiter);
&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;
result.Remove(--result.Length, 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;
result.Append(&lt;span style="color: #2b91af"&gt;Environment&lt;/span&gt;.NewLine);
&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; }
&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; &lt;span style="color: blue"&gt;foreach&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;DataRow&lt;/span&gt; row &lt;span style="color: blue"&gt;in&lt;/span&gt; table.Rows)
&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; {
&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;object&lt;/span&gt; item &lt;span style="color: blue"&gt;in&lt;/span&gt; row.ItemArray)
&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;&amp;nbsp; &lt;span style="color: blue"&gt;if&lt;/span&gt; (item &lt;span style="color: blue"&gt;is&lt;/span&gt; System.&lt;span style="color: #2b91af"&gt;DBNull&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
result.Append(delimiter);
&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; &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;&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; &lt;span style="color: blue"&gt;string&lt;/span&gt; itemAsString
= item.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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="background: #ffffbf"&gt;//
Double up all embedded double quotes&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
itemAsString = itemAsString.Replace(&lt;span style="background: #e5e5e5"&gt;"\""&lt;/span&gt;, &lt;span style="background: #e5e5e5"&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;&amp;nbsp;&amp;nbsp;&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="background: #ffffbf"&gt;//
To keep things simple, always delimit with double-quotes&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="background: #ffffbf"&gt;//
so we don't have to determine in which cases they're necessary&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="background: #ffffbf"&gt;//
and which cases they're not.&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
itemAsString = &lt;span style="background: #e5e5e5"&gt;"\""&lt;/span&gt; + itemAsString + &lt;span style="background: #e5e5e5"&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
result.Append(itemAsString + delimiter);
&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;
}
&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;
result.Remove(--result.Length, 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;
result.Append(&lt;span style="color: #2b91af"&gt;Environment&lt;/span&gt;.NewLine);
&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; }
&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; &lt;span style="color: blue"&gt;return&lt;/span&gt; result.ToString();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&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; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=32a4ffa4-0389-4b6c-94a3-3f637f5cac89" /&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,32a4ffa4-0389-4b6c-94a3-3f637f5cac89.aspx</comments>
      <category>.NET</category>
      <category>C#</category>
    </item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=46c2ad44-1dcb-4363-b727-050ee2494dfb</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,46c2ad44-1dcb-4363-b727-050ee2494dfb.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,46c2ad44-1dcb-4363-b727-050ee2494dfb.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=46c2ad44-1dcb-4363-b727-050ee2494dfb</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <style type="text/css">
.code { background-color: #efefef; font-family:consolas,courier new; }
</style>
        <p>
I recently added a maintenance form to our website which allows a user to add and
delete entries to a list of banner ads stored in a simple XML file. Previously we've
just been maintaining them manually by editing the XML directly and copying the associated
banner images into a folder on the website. When you delete an ad, I decided to NOT
delete the associated image since they may be reused (and I wanted to avoid forcing
the user to upload the image again). However, we'd still like to periodically clean
out this folder and "archive" the images so they're not cluttering up the selection
screen.
</p>
        <p>
I basically needed some code which would get me a list of files in the banner images
folder which were not referenced in my banner XML file. It can be kind of clunky to
iterate through XML but they've made it much easier with the introduction of LINQ.
I fired up LINQPad (which, BTW, is an AWESOME free tool for testing out LINQ code)
and tried out a few ideas. As a side note, it looks like Intellisense is now available
if you purchase a copy of LINQPad.
</p>
        <p>
          <a href="http://www.linqpad.net/">http://www.linqpad.net/</a>
        </p>
        <p>
I started with querying the filesystem to get a list of files:
</p>
   
<div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"><p style="margin: 0px"><span style="color: #2b91af">DirectoryInfo</span> info = <span style="color: blue">new</span><span style="color: #2b91af">DirectoryInfo</span>(<span style="color: #a31515">@"X:\inetpub\wwwroot\images\banner"</span>);
</p><p style="margin: 0px"><span style="color: #2b91af">FileInfo</span>[] files = info.GetFiles();
</p><p style="margin: 0px">
 
</p><p style="margin: 0px">
files.Dump();
</p><p style="margin: 0px">
 
</p></div><p>
.Dump() is an extension method available in LINQPad which dumps out the results of
the query (we haven't actually used LINQ yet to do anything). 
</p><p>
Here's what it looks like: 
</p><p><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="308" alt="FileInfoLinq" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/LINQQueriesXMLandtheFilesystem_C03C/FileInfoLinq_3.png" width="780" border="0" /></p><p>
You might notice that Directory contains a DirectyInfo element. If you click on the
down arrow it will expand out these values as well. 
</p><p>
So I now had a list of files, I wanted to then get a list of images referenced in
my banner file. Here's the format of the XML file:
</p><pre><p>
&lt;News&gt;    
<br />
   &lt;NewsItem&gt;<br />
       &lt;Title&gt;Supertooth3-banner.gif&lt;/Title&gt;<br />
       &lt;Image&gt;/images/banner/Supertooth3-banner.gif&lt;/Image&gt;<br />
       &lt;Height&gt;183&lt;/Height&gt;<br />
       &lt;Link&gt;/PortalView.aspx?navto=/Supertooth3-banner.gif&lt;/Link&gt;<br />
       &lt;Date&gt;July, 19th, 2003&lt;/Date&gt;<br />
       &lt;Target&gt;&lt;/Target&gt;<br />
   &lt;/NewsItem&gt;    
</p><p>
   
</p><p>
 
</p></pre><p>
I haven't really been using Title for anything besides the name of the image file,
so I was able to take a bit of a shortcut here and use it for my comparison. To pull
out the list of images used in the XML, I wrote this query: 
</p><div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"><p style="margin: 0px"><span style="color: #2b91af">XDocument</span> doc = System.Xml.Linq.<span style="color: #2b91af">XDocument</span>.Load(<span style="color: #a31515">@"X:\inetpub\wwwroot\adv.xml"</span>);
</p><p style="margin: 0px">
doc.Dump();
</p><p style="margin: 0px">
 
</p><p style="margin: 0px"><span style="color: blue">var</span> news = <span style="color: blue">from</span> item <span style="color: blue">in</span> doc.Descendants(<span style="background: #e5e5e5">"Title"</span>)
</p><p style="margin: 0px">
           <span style="color: blue">orderby</span> item.Value
</p><p style="margin: 0px">
           <span style="color: blue">select</span> item.Value;
</p><p style="margin: 0px">
news.Dump();
</p></div><p>
 
</p><p>
Which produces this: 
</p><p><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="221" alt="XmlTitlesLinq" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/LINQQueriesXMLandtheFilesystem_C03C/XmlTitlesLinq_3.png" width="267" border="0" /></p><p>
I noticed that the banner images folder contained a bunch of other files that I really
didn't want to consider for filtering, so I needed to narrow my query to files that
had specific extensions. C# doesn't really have a direct equivalent for INLIST, but
we can do this a slightly different way for the same effect. 
</p><p>
First I define an array of valid extensions, then (inside the where clause of the
LINQ query) I check to see if this list of file types contains the filetype of the
file I'm currently evaluating. It's a bit backwards, but it's simple and it works. 
</p><div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"><p style="margin: 0px"><span style="color: blue">string</span>[] fileTypes = { <span style="background: #e5e5e5">".jpg"</span>, <span style="background: #e5e5e5">".gif"</span>, <span style="background: #e5e5e5">".png"</span> };
</p><p style="margin: 0px"><span style="color: blue">var</span> imgFiles = <span style="color: blue">from</span> file <span style="color: blue">in</span> files
</p><p style="margin: 0px">
               <span style="color: blue">where</span> (fileTypes.Contains(file.Extension))
</p><p style="margin: 0px">
               <span style="color: blue">orderby</span> file.Name
</p><p style="margin: 0px">
               <span style="color: blue">select</span> file.Name;
</p><p style="margin: 0px">
 
</p><p style="margin: 0px">
imgFiles.Dump();
</p><p style="margin: 0px">
 
</p></div><p>
Now I've got a list of files from my XML and a list of files from the banner images
folder. I want to get a list of files from the banner images folder that aren't in
the XML list. I do this via a final query: 
</p><div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"><p style="margin: 0px"><span style="color: blue">var</span> extra = <span style="color: blue">from</span> singleFile <span style="color: blue">in</span> imgFiles
</p><p style="margin: 0px">
            <span style="color: blue">where</span> !(news.Contains(singleFile))
</p><p style="margin: 0px">
            <span style="color: blue">select</span> singleFile;
</p><p style="margin: 0px">
extra.Dump();    
</p></div><p>
This returns my extra files. Now I can just use this list to move my images into an
archive folder periodically. 
</p><p>
If I put it all together, I end up with this:
</p><div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"><p style="margin: 0px"><span style="color: #2b91af"></span> 
</p><p style="margin: 0px"><span style="color: #2b91af">XDocument</span> doc = System.Xml.Linq.<span style="color: #2b91af">XDocument</span>.Load(<span style="color: #a31515">@"X:\inetpub\wwwroot\adv.xml"</span>);
</p><p style="margin: 0px"><span style="color: #2b91af">DirectoryInfo</span> info = <span style="color: blue">new</span><span style="color: #2b91af">DirectoryInfo</span>(<span style="color: #a31515">@"X:\inetpub\wwwroot\images\banner"</span>);
</p><p style="margin: 0px"><span style="color: #2b91af">FileInfo</span>[] files = info.GetFiles();
</p><p style="margin: 0px">
doc.Dump();
</p><p style="margin: 0px">
files.Dump();
</p><p style="margin: 0px">
 
</p><p style="margin: 0px"><span style="color: blue">var</span> news = <span style="color: blue">from</span> item <span style="color: blue">in</span> doc.Descendants(<span style="background: #e5e5e5">"Title"</span>)
</p><p style="margin: 0px">
           <span style="color: blue">orderby</span> item.Value
</p><p style="margin: 0px">
           <span style="color: blue">select</span> item.Value;
</p><p style="margin: 0px">
news.Dump();
</p><p style="margin: 0px"><span style="color: blue">string</span>[] fileTypes = { <span style="background: #e5e5e5">".jpg"</span>, <span style="background: #e5e5e5">".gif"</span>, <span style="background: #e5e5e5">".png"</span> };
</p><p style="margin: 0px"><span style="color: blue">var</span> imgFiles = <span style="color: blue">from</span> file <span style="color: blue">in</span> files
</p><p style="margin: 0px">
               <span style="color: blue">where</span> (fileTypes.Contains(file.Extension))
</p><p style="margin: 0px">
               <span style="color: blue">orderby</span> file.Name
</p><p style="margin: 0px">
               <span style="color: blue">select</span> file.Name;
</p><p style="margin: 0px">
 
</p><p style="margin: 0px">
imgFiles.Dump();
</p><p style="margin: 0px">
 
</p><p style="margin: 0px"><span style="color: blue">var</span> extra = <span style="color: blue">from</span> singleFile <span style="color: blue">in</span> imgFiles
</p><p style="margin: 0px">
            <span style="color: blue">where</span> !(news.Contains(singleFile))
</p><p style="margin: 0px">
            <span style="color: blue">select</span> singleFile;
</p><p style="margin: 0px">
extra.Dump();    
</p></div><p><strong>Links:</strong></p><p><a href="http://www.linqpad.net/">http://www.linqpad.net/</a></p><img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=46c2ad44-1dcb-4363-b727-050ee2494dfb" /></body>
      <title>LINQ Queries - XML and the Filesystem</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,46c2ad44-1dcb-4363-b727-050ee2494dfb.aspx</guid>
      <link>http://www.rcs-solutions.com/blog/2008/11/30/LINQQueriesXMLAndTheFilesystem.aspx</link>
      <pubDate>Sun, 30 Nov 2008 18:46:11 GMT</pubDate>
      <description> &lt;style type="text/css"&gt;
.code { background-color: #efefef; font-family:consolas,courier new; }
&lt;/style&gt;
&lt;p&gt;
I recently added a maintenance form to our website which allows a user to add and
delete entries to a list of banner ads stored in a simple XML file. Previously we've
just been maintaining them manually by editing the XML directly and copying the associated
banner images into a folder on the website. When you delete an ad, I decided to NOT
delete the associated image since they may be reused (and I wanted to avoid forcing
the user to upload the image again). However, we'd still like to periodically clean
out this folder and "archive" the images so they're not cluttering up the selection
screen.
&lt;/p&gt;
&lt;p&gt;
I basically needed some code which would get me a list of files in the banner images
folder which were not referenced in my banner XML file. It can be kind of clunky to
iterate through XML but they've made it much easier with the introduction of LINQ.
I fired up LINQPad (which, BTW, is an AWESOME free tool for testing out LINQ code)
and tried out a few ideas. As a side note, it looks like Intellisense is now available
if you purchase a copy of LINQPad.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.linqpad.net/"&gt;http://www.linqpad.net/&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
I started with querying the filesystem to get a list of files:
&lt;/p&gt;
&amp;nbsp;&amp;nbsp; 
&lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;DirectoryInfo&lt;/span&gt; info = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;DirectoryInfo&lt;/span&gt;(&lt;span style="color: #a31515"&gt;@"X:\inetpub\wwwroot\images\banner"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;FileInfo&lt;/span&gt;[] files = info.GetFiles();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
files.Dump();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
.Dump() is an extension method available in LINQPad which dumps out the results of
the query (we haven't actually used LINQ yet to do anything). 
&lt;/p&gt;
&lt;p&gt;
Here's what it looks like: 
&lt;/p&gt;
&lt;p&gt;
&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="308" alt="FileInfoLinq" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/LINQQueriesXMLandtheFilesystem_C03C/FileInfoLinq_3.png" width="780" border="0"&gt; 
&lt;p&gt;
You might notice that Directory contains a DirectyInfo element. If you click on the
down arrow it will expand out these values as well. 
&lt;/p&gt;
&lt;p&gt;
So I now had a list of files, I wanted to then get a list of images referenced in
my banner file. Here's the format of the XML file:
&lt;/p&gt;
&lt;pre&gt;
&lt;p&gt;
&amp;lt;News&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;lt;NewsItem&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Title&amp;gt;Supertooth3-banner.gif&amp;lt;/Title&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Image&amp;gt;/images/banner/Supertooth3-banner.gif&amp;lt;/Image&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Height&amp;gt;183&amp;lt;/Height&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Link&amp;gt;/PortalView.aspx?navto=/Supertooth3-banner.gif&amp;lt;/Link&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Date&amp;gt;July, 19th, 2003&amp;lt;/Date&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Target&amp;gt;&amp;lt;/Target&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;lt;/NewsItem&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;p&gt;
&amp;nbsp;&amp;nbsp; 
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;/pre&gt;
&lt;p&gt;
I haven't really been using Title for anything besides the name of the image file,
so I was able to take a bit of a shortcut here and use it for my comparison. To pull
out the list of images used in the XML, I wrote this query: 
&lt;/p&gt;
&lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;XDocument&lt;/span&gt; doc = System.Xml.Linq.&lt;span style="color: #2b91af"&gt;XDocument&lt;/span&gt;.Load(&lt;span style="color: #a31515"&gt;@"X:\inetpub\wwwroot\adv.xml"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
doc.Dump();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;var&lt;/span&gt; news = &lt;span style="color: blue"&gt;from&lt;/span&gt; item &lt;span style="color: blue"&gt;in&lt;/span&gt; doc.Descendants(&lt;span style="background: #e5e5e5"&gt;"Title"&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; &lt;span style="color: blue"&gt;orderby&lt;/span&gt; item.Value
&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; &lt;span style="color: blue"&gt;select&lt;/span&gt; item.Value;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
news.Dump();
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
Which produces this: 
&lt;/p&gt;
&lt;p&gt;
&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="221" alt="XmlTitlesLinq" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/LINQQueriesXMLandtheFilesystem_C03C/XmlTitlesLinq_3.png" width="267" border="0"&gt; 
&lt;/p&gt;
&lt;p&gt;
I noticed that the banner images folder contained a bunch of other files that I really
didn't want to consider for filtering, so I needed to narrow my query to files that
had specific extensions. C# doesn't really have a direct equivalent for INLIST, but
we can do this a slightly different way for the same effect. 
&lt;/p&gt;
&lt;p&gt;
First I define an array of valid extensions, then (inside the where clause of the
LINQ query) I check to see if this list of file types contains the filetype of the
file I'm currently evaluating. It's a bit backwards, but it's simple and it works. 
&lt;/p&gt;
&lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;string&lt;/span&gt;[] fileTypes = { &lt;span style="background: #e5e5e5"&gt;".jpg"&lt;/span&gt;, &lt;span style="background: #e5e5e5"&gt;".gif"&lt;/span&gt;, &lt;span style="background: #e5e5e5"&gt;".png"&lt;/span&gt; };
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;var&lt;/span&gt; imgFiles = &lt;span style="color: blue"&gt;from&lt;/span&gt; file &lt;span style="color: blue"&gt;in&lt;/span&gt; files
&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; &lt;span style="color: blue"&gt;where&lt;/span&gt; (fileTypes.Contains(file.Extension))
&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; &lt;span style="color: blue"&gt;orderby&lt;/span&gt; file.Name
&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; &lt;span style="color: blue"&gt;select&lt;/span&gt; file.Name;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
imgFiles.Dump();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Now I've got a list of files from my XML and a list of files from the banner images
folder. I want to get a list of files from the banner images folder that aren't in
the XML list. I do this via a final query: 
&lt;/p&gt;
&lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;var&lt;/span&gt; extra = &lt;span style="color: blue"&gt;from&lt;/span&gt; singleFile &lt;span style="color: blue"&gt;in&lt;/span&gt; imgFiles
&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; &lt;span style="color: blue"&gt;where&lt;/span&gt; !(news.Contains(singleFile))
&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; &lt;span style="color: blue"&gt;select&lt;/span&gt; singleFile;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
extra.Dump();&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
This returns my extra files. Now I can just use this list to move my images into an
archive folder periodically. 
&lt;/p&gt;
&lt;p&gt;
If I put it all together, I end up with this:
&lt;/p&gt;
&lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&lt;/span&gt;&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;XDocument&lt;/span&gt; doc = System.Xml.Linq.&lt;span style="color: #2b91af"&gt;XDocument&lt;/span&gt;.Load(&lt;span style="color: #a31515"&gt;@"X:\inetpub\wwwroot\adv.xml"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;DirectoryInfo&lt;/span&gt; info = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;DirectoryInfo&lt;/span&gt;(&lt;span style="color: #a31515"&gt;@"X:\inetpub\wwwroot\images\banner"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;FileInfo&lt;/span&gt;[] files = info.GetFiles();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
doc.Dump();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
files.Dump();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;var&lt;/span&gt; news = &lt;span style="color: blue"&gt;from&lt;/span&gt; item &lt;span style="color: blue"&gt;in&lt;/span&gt; doc.Descendants(&lt;span style="background: #e5e5e5"&gt;"Title"&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; &lt;span style="color: blue"&gt;orderby&lt;/span&gt; item.Value
&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; &lt;span style="color: blue"&gt;select&lt;/span&gt; item.Value;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
news.Dump();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;string&lt;/span&gt;[] fileTypes = { &lt;span style="background: #e5e5e5"&gt;".jpg"&lt;/span&gt;, &lt;span style="background: #e5e5e5"&gt;".gif"&lt;/span&gt;, &lt;span style="background: #e5e5e5"&gt;".png"&lt;/span&gt; };
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;var&lt;/span&gt; imgFiles = &lt;span style="color: blue"&gt;from&lt;/span&gt; file &lt;span style="color: blue"&gt;in&lt;/span&gt; files
&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; &lt;span style="color: blue"&gt;where&lt;/span&gt; (fileTypes.Contains(file.Extension))
&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; &lt;span style="color: blue"&gt;orderby&lt;/span&gt; file.Name
&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; &lt;span style="color: blue"&gt;select&lt;/span&gt; file.Name;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
imgFiles.Dump();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;var&lt;/span&gt; extra = &lt;span style="color: blue"&gt;from&lt;/span&gt; singleFile &lt;span style="color: blue"&gt;in&lt;/span&gt; imgFiles
&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; &lt;span style="color: blue"&gt;where&lt;/span&gt; !(news.Contains(singleFile))
&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; &lt;span style="color: blue"&gt;select&lt;/span&gt; singleFile;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
extra.Dump();&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;strong&gt;Links:&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.linqpad.net/"&gt;http://www.linqpad.net/&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=46c2ad44-1dcb-4363-b727-050ee2494dfb" /&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,46c2ad44-1dcb-4363-b727-050ee2494dfb.aspx</comments>
      <category>.NET</category>
      <category>C#</category>
      <category>LINQ</category>
    </item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=3a94f39a-2646-427e-8d72-7922ec1356b8</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,3a94f39a-2646-427e-8d72-7922ec1356b8.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,3a94f39a-2646-427e-8d72-7922ec1356b8.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=3a94f39a-2646-427e-8d72-7922ec1356b8</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I thought this was an interesting question that has come up a couple of times in the
last few days over on the Universal Thread. In VFP you can create a subclass of a
form, customize it, then configure VFP to use this subclass as the "template" for
any new forms you create (by going into Tools &gt; Options &gt; Forms and setting
the base class). 
</p>
        <p>
The question was, how do I do this in .NET? 
</p>
        <p>
It's pretty easy - create your form and add any controls, methods, properties, etc.
that you want. Then go to File &gt; Export Template. An Export Template Wizard will
open. Change the selection to an "Item template" and click Next. 
</p>
        <p>
          <img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="452" alt="Export Template Wizard" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/VisualStudioTemplates_124CD/ExportTemplate_3.png" width="580" border="0" />
        </p>
        <p>
  
</p>
        <p>
On the next screen put a checkmark next to the item(s) you want included in the template.
If you have other dependencies (like external classes) you can also select them here.
Then click Next again. 
</p>
        <p>
          <img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="244" alt="Export Template Wizard Select Item to Export" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/VisualStudioTemplates_124CD/ExportTemplateWizard2_3.png" width="224" border="0" />
        </p>
        <p>
Now you can select any external references you want to include. For example, if you
created a project which includes a set of base controls that you used on your form,
you may want to select them here (so when you use this template these references will
automatically get added to your project). Click Next. 
</p>
        <p>
          <img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="225" alt="Export Template Wizard Select Item References" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/VisualStudioTemplates_124CD/ExportTemplateWizard3_3.png" width="283" border="0" />
        </p>
        <p>
Finally you can select an icon that is associate with this template, enter the template
name, description, and it's output location. I'd suggest leaving the "Automatically
import the template into Visual Studio" option checked. If you don't like the output
location, unfortunately you can't change it here. You have to change it via Tools
&gt; Options &gt; Projects and Solutions. Finally click Finish. 
</p>
        <p>
          <img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="332" alt="Export Template Wizard Select Template Options" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/VisualStudioTemplates_124CD/ExportTemplateWizard4_3.png" width="589" border="0" />
        </p>
        <p>
At this point, when you do an "Add New Item" you should be able to scroll to the bottom
of the templates and see "My Templates" - the new template you created should exist
there. 
</p>
        <p>
Although I showed this for a WinForms application, this can actually be used with
any class (and for ASP.NET applications). For example, I have a base business object
class I use. Every time I create a new one I just select a template based on a subclass
of it to create the new one. 
</p>
        <img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=3a94f39a-2646-427e-8d72-7922ec1356b8" />
      </body>
      <title>Visual Studio Templates</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,3a94f39a-2646-427e-8d72-7922ec1356b8.aspx</guid>
      <link>http://www.rcs-solutions.com/blog/2008/11/27/VisualStudioTemplates.aspx</link>
      <pubDate>Thu, 27 Nov 2008 01:50:46 GMT</pubDate>
      <description>&lt;p&gt;
I thought this was an interesting question that has come up a couple of times in the
last few days over on the Universal Thread. In VFP you can create a subclass of a
form, customize it, then configure VFP to use this subclass as the "template" for
any new forms you create (by going into Tools &amp;gt; Options &amp;gt; Forms and setting
the base class). 
&lt;/p&gt;
&lt;p&gt;
The question was, how do I do this in .NET? 
&lt;/p&gt;
&lt;p&gt;
It's pretty easy - create your form and add any controls, methods, properties, etc.
that you want. Then go to File &amp;gt; Export Template. An Export Template Wizard will
open. Change the selection to an "Item template" and click Next. 
&lt;/p&gt;
&lt;p&gt;
&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="452" alt="Export Template Wizard" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/VisualStudioTemplates_124CD/ExportTemplate_3.png" width="580" border="0"&gt; 
&lt;p&gt;
&amp;nbsp; 
&lt;p&gt;
On the next screen put a checkmark next to the item(s) you want included in the template.
If you have other dependencies (like external classes) you can also select them here.
Then click Next again. 
&lt;/p&gt;
&lt;p&gt;
&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="244" alt="Export Template Wizard Select Item to Export" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/VisualStudioTemplates_124CD/ExportTemplateWizard2_3.png" width="224" border="0"&gt; 
&lt;p&gt;
Now you can select any external references you want to include. For example, if you
created a project which includes a set of base controls that you used on your form,
you may want to select them here (so when you use this template these references will
automatically get added to your project). Click Next. 
&lt;/p&gt;
&lt;p&gt;
&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="225" alt="Export Template Wizard Select Item References" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/VisualStudioTemplates_124CD/ExportTemplateWizard3_3.png" width="283" border="0"&gt; 
&lt;p&gt;
Finally you can select an icon that is associate with this template, enter the template
name, description, and it's output location. I'd suggest leaving the "Automatically
import the template into Visual Studio" option checked. If you don't like the output
location, unfortunately you can't change it here. You have to change it via Tools
&amp;gt; Options &amp;gt; Projects and Solutions. Finally click Finish. 
&lt;/p&gt;
&lt;p&gt;
&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="332" alt="Export Template Wizard Select Template Options" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/VisualStudioTemplates_124CD/ExportTemplateWizard4_3.png" width="589" border="0"&gt; 
&lt;p&gt;
At this point, when you do an "Add New Item" you should be able to scroll to the bottom
of the templates and see "My Templates" - the new template you created should exist
there. 
&lt;/p&gt;
&lt;p&gt;
Although I showed this for a WinForms application, this can actually be used with
any class (and for ASP.NET applications). For example, I have a base business object
class I use. Every time I create a new one I just select a template based on a subclass
of it to create the new one. 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=3a94f39a-2646-427e-8d72-7922ec1356b8" /&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,3a94f39a-2646-427e-8d72-7922ec1356b8.aspx</comments>
      <category>.NET</category>
      <category>Visual Studio</category>
    </item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=0c45f600-d3fb-4838-b823-5a88fe39fd0c</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,0c45f600-d3fb-4838-b823-5a88fe39fd0c.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,0c45f600-d3fb-4838-b823-5a88fe39fd0c.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=0c45f600-d3fb-4838-b823-5a88fe39fd0c</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I ran across a really cool .NET library on a recent project I've been working on.
We have an internal website where we post news, documentation, etc. - basically a
Content Management System (CMS). We're working on a new set of documentation that
is being done inside of a third party help builder application. We need to import
the HTML files it generates into our website (so we get all the things it offers,
like security, searching, revision tracking, view statistics, etc.). So basically,
I need to run through a lot of HTML files, build a tree of the documents (similar
to the help file) and rewrite all of the URL's and image links to point to the correct
URL inside of the site. I initially started looking at various regular expressions
that I might be able to use over at <a href="http://regexlib.com/" target="_blank">http://regexlib.com/</a>.
Almost every single one of them had some comment about it failing under some circumstances.
The HTML is surprisingly clean, but I was still nervous about it. So I looked at using <a href="http://www.devincook.com/goldparser/" target="_blank">GOLD</a> to
parse the HTML. However, from some of the comments I found it still didn't make everything
as easy I would have liked. I finally ran across <a href="http://www.codeplex.com/htmlagilitypack" target="_blank">HtmlAgilityPack</a> over
on CodePlex . It's a .NET library which lets you read AND write changes to an HTML
file via a simple API. 
</p>
        <p>
Here's a chunk of code from my importer so you can get a feel for how it works: 
</p>
        <div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new">
          <p style="margin: 0px">
            <span style="color: #2b91af">HtmlDocument</span> doc = <span style="color: blue">new</span><span style="color: #2b91af">HtmlDocument</span>();
</p>
          <p style="margin: 0px">
doc.Load(content.FullDocumentPath);
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">HtmlNodeCollection</span> linkNodes = doc.DocumentNode.SelectNodes(<span style="background: #e5e5e5">"//a/@href"</span>);
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">Content</span> match = <span style="color: blue">null</span>;
</p>
          <p style="margin: 0px">
            <span style="background: #ffffbf">// Run only if there are links in the document.</span>
          </p>
          <p style="margin: 0px">
            <span style="color: blue">if</span> (linkNodes != <span style="color: blue">null</span>)
</p>
          <p style="margin: 0px">
{
</p>
          <p style="margin: 0px">
    <span style="background: #ffffbf">// Fix up the URL's</span></p>
          <p style="margin: 0px">
    <span style="color: blue">foreach</span> (<span style="color: #2b91af">HtmlNode</span> linkNode <span style="color: blue">in</span> linkNodes)
</p>
          <p style="margin: 0px">
    {
</p>
          <p style="margin: 0px">
        <span style="color: #2b91af">HtmlAttribute</span> attrib
= linkNode.Attributes[<span style="background: #e5e5e5">"href"</span>];
</p>
          <p style="margin: 0px">
        <span style="background: #ffffbf">// If
it's an internal page anchor, ignore it</span></p>
          <p style="margin: 0px">
        <span style="color: blue">if</span> (attrib.Value.StartsWith(<span style="background: #e5e5e5">"#"</span>))
</p>
          <p style="margin: 0px">
            <span style="color: blue">continue</span>;
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
        <span style="color: blue">string</span> path
= <span style="color: blue">this</span>.GetAbsolutePath(content.DocumentLink, attrib.Value);
</p>
          <p style="margin: 0px">
        match = <span style="color: blue">this</span>.m_contentList.Find(p
=&gt; p.DocumentLink == path);
</p>
          <p style="margin: 0px">
 
</p>
          <p style="margin: 0px">
        <span style="color: blue">if</span> (match
!= <span style="color: blue">null</span>)
</p>
          <p style="margin: 0px">
            attrib.Value =
match.GetUrl();
</p>
          <p style="margin: 0px">
        <span style="color: blue">else</span><span style="color: blue">if</span> (!path.ToLower().StartsWith(<span style="background: #e5e5e5">"http://"</span>)
&amp;&amp; !path.ToLower().StartsWith(<span style="background: #e5e5e5">"mailto:"</span>))
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">Console</span>.WriteLine(<span style="background: #e5e5e5">"Cannot
find matching document, searched for "</span> + path);                        
</p>
          <p style="margin: 0px">
    }
</p>
          <p style="margin: 0px">
}
</p>
          <p style="margin: 0px">
 
</p>
        </div>
        <p>
Basically, doc.DocumentNode.SelectNodes("//a/@href") returns a collection of links
in the document (it uses XPath syntax for the selection string). From there, I just
iterate through them, build the new URL, then save the modified Url via code that
just does: linkNode.Attributes["href"].Value = "New URL Here". I also needed to strip
out all the script tags inside of the document, so it uses similar syntax: 
</p>
        <div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new">
          <p style="margin: 0px">
            <span style="color: blue">private</span>
            <span style="color: blue">void</span> StripOutScripts(<span style="color: #2b91af">HtmlDocument</span> doc)
</p>
          <p style="margin: 0px">
{
</p>
          <p style="margin: 0px">
    <span style="background: #ffffbf">// Strip out the scripts</span></p>
          <p style="margin: 0px">
    <span style="color: #2b91af">HtmlNodeCollection</span> scriptNodes
= doc.DocumentNode.SelectNodes(<span style="background: #e5e5e5">"//script"</span>);
</p>
          <p style="margin: 0px">
    <span style="color: blue">if</span> (scriptNodes != <span style="color: blue">null</span>)
</p>
          <p style="margin: 0px">
    {
</p>
          <p style="margin: 0px">
        <span style="color: blue">foreach</span> (<span style="color: #2b91af">HtmlNode</span> scriptNode <span style="color: blue">in</span> scriptNodes)
</p>
          <p style="margin: 0px">
        {
</p>
          <p style="margin: 0px">
            scriptNode.ParentNode.RemoveChild(scriptNode, <span style="color: blue">false</span>);
</p>
          <p style="margin: 0px">
        }
</p>
          <p style="margin: 0px">
    }
</p>
          <p style="margin: 0px">
}
</p>
          <p style="margin: 0px">
 
</p>
        </div>
        <p>
I do the same sort of thing - iterate over the collection, except this time tell it
to remove the nodes from the document (note that I'm grabbing the parent node, since
the current node is everything contained within the script, excluding the &lt;script&gt;
tags. By getting the parent, we get that and the tags themselves.
</p>
        <p>
Each collection has a WriteContentTo() method which can write the HTML for that section
of the document to a Stream. What's really nice about this entire library (besides
how simple it was to use) was the fact that it doesn't seem to mangle the existing
HTML when using WriteContentTo() (at least from what I've seen). Only one minor complaint
- the docs are a bit weak. It just includes the standard documentation of the classes,
not much in the way of examples. However, it's pretty consistent so it doesn't take
much to get started with it.
</p>
        <p>
What a great library - it couldn't be simpler. It saved me a ton of time.
</p>
        <p>
          <strong>Links:</strong>
        </p>
        <p>
          <a href="http://www.codeplex.com/htmlagilitypack">http://www.codeplex.com/htmlagilitypack</a>
          <br />
          <a href="http://regexlib.com/">http://regexlib.com/</a>
          <br />
          <a href="http://www.devincook.com/goldparser/">http://www.devincook.com/goldparser/</a>
        </p>
        <img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=0c45f600-d3fb-4838-b823-5a88fe39fd0c" />
      </body>
      <title>Processing HTML Documents</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,0c45f600-d3fb-4838-b823-5a88fe39fd0c.aspx</guid>
      <link>http://www.rcs-solutions.com/blog/2008/08/13/ProcessingHTMLDocuments.aspx</link>
      <pubDate>Wed, 13 Aug 2008 02:17:44 GMT</pubDate>
      <description>&lt;p&gt;
I ran across a really cool .NET library on a recent project I've been working on.
We have an internal website where we post news, documentation, etc. - basically a
Content Management System (CMS). We're working on a new set of documentation that
is being done inside of a third party help builder application. We need to import
the HTML files it generates into our website (so we get all the things it offers,
like security, searching, revision tracking, view statistics, etc.). So basically,
I need to run through a lot of HTML files, build a tree of the documents (similar
to the help file) and rewrite all of the URL's and image links to point to the correct
URL inside of the site. I initially started looking at various regular expressions
that I might be able to use over at &lt;a href="http://regexlib.com/" target="_blank"&gt;http://regexlib.com/&lt;/a&gt;.
Almost every single one of them had some comment about it failing under some circumstances.
The HTML is surprisingly clean, but I was still nervous about it. So I looked at using &lt;a href="http://www.devincook.com/goldparser/" target="_blank"&gt;GOLD&lt;/a&gt; to
parse the HTML. However, from some of the comments I found it still didn't make everything
as easy I would have liked. I finally ran across &lt;a href="http://www.codeplex.com/htmlagilitypack" target="_blank"&gt;HtmlAgilityPack&lt;/a&gt; over
on CodePlex . It's a .NET library which lets you read AND write changes to an HTML
file via a simple API. 
&lt;/p&gt;
&lt;p&gt;
Here's a chunk of code from my importer so you can get a feel for how it works: 
&lt;/p&gt;
&lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;HtmlDocument&lt;/span&gt; doc = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;HtmlDocument&lt;/span&gt;();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
doc.Load(content.FullDocumentPath);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;HtmlNodeCollection&lt;/span&gt; linkNodes = doc.DocumentNode.SelectNodes(&lt;span style="background: #e5e5e5"&gt;"//a/@href"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;Content&lt;/span&gt; match = &lt;span style="color: blue"&gt;null&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="background: #ffffbf"&gt;// Run only if there are links in the document.&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;if&lt;/span&gt; (linkNodes != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
&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="background: #ffffbf"&gt;// Fix up the URL's&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;foreach&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;HtmlNode&lt;/span&gt; linkNode &lt;span style="color: blue"&gt;in&lt;/span&gt; linkNodes)
&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;&amp;nbsp; &lt;span style="color: #2b91af"&gt;HtmlAttribute&lt;/span&gt; attrib
= linkNode.Attributes[&lt;span style="background: #e5e5e5"&gt;"href"&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; &lt;span style="background: #ffffbf"&gt;// If
it's an internal page anchor, ignore it&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; &lt;span style="color: blue"&gt;if&lt;/span&gt; (attrib.Value.StartsWith(&lt;span style="background: #e5e5e5"&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;continue&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; &lt;span style="color: blue"&gt;string&lt;/span&gt; path
= &lt;span style="color: blue"&gt;this&lt;/span&gt;.GetAbsolutePath(content.DocumentLink, attrib.Value);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; match = &lt;span style="color: blue"&gt;this&lt;/span&gt;.m_contentList.Find(p
=&amp;gt; p.DocumentLink == path);
&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; &lt;span style="color: blue"&gt;if&lt;/span&gt; (match
!= &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; attrib.Value =
match.GetUrl();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&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;span style="color: blue"&gt;if&lt;/span&gt; (!path.ToLower().StartsWith(&lt;span style="background: #e5e5e5"&gt;"http://"&lt;/span&gt;)
&amp;amp;&amp;amp; !path.ToLower().StartsWith(&lt;span style="background: #e5e5e5"&gt;"mailto:"&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; &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="background: #e5e5e5"&gt;"Cannot
find matching document, searched for "&lt;/span&gt; + path);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&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; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Basically, doc.DocumentNode.SelectNodes("//a/@href") returns a collection of links
in the document (it uses XPath syntax for the selection string). From there, I just
iterate through them, build the new URL, then save the modified Url via code that
just does: linkNode.Attributes["href"].Value = "New URL Here". I also needed to strip
out all the script tags inside of the document, so it uses similar syntax: 
&lt;/p&gt;
&lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; StripOutScripts(&lt;span style="color: #2b91af"&gt;HtmlDocument&lt;/span&gt; doc)
&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="background: #ffffbf"&gt;// Strip out the scripts&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;HtmlNodeCollection&lt;/span&gt; scriptNodes
= doc.DocumentNode.SelectNodes(&lt;span style="background: #e5e5e5"&gt;"//script"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;if&lt;/span&gt; (scriptNodes != &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;/p&gt;
&lt;p style="margin: 0px"&gt;
&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: #2b91af"&gt;HtmlNode&lt;/span&gt; scriptNode &lt;span style="color: blue"&gt;in&lt;/span&gt; scriptNodes)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&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; scriptNode.ParentNode.RemoveChild(scriptNode, &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; }
&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;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
I do the same sort of thing - iterate over the collection, except this time tell it
to remove the nodes from the document (note that I'm grabbing the parent node, since
the current node is everything contained within the script, excluding the &amp;lt;script&amp;gt;
tags. By getting the parent, we get that and the tags themselves.
&lt;/p&gt;
&lt;p&gt;
Each collection has a WriteContentTo() method which can write the HTML for that section
of the document to a Stream. What's really nice about this entire library (besides
how simple it was to use) was the fact that it doesn't seem to mangle the existing
HTML when using WriteContentTo() (at least from what I've seen). Only one minor complaint
- the docs are a bit weak. It just includes the standard documentation of the classes,
not much in the way of examples. However, it's pretty consistent so it doesn't take
much to get started with it.
&lt;/p&gt;
&lt;p&gt;
What a great library - it couldn't be simpler. It saved me a ton of time.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Links:&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.codeplex.com/htmlagilitypack"&gt;http://www.codeplex.com/htmlagilitypack&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://regexlib.com/"&gt;http://regexlib.com/&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://www.devincook.com/goldparser/"&gt;http://www.devincook.com/goldparser/&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=0c45f600-d3fb-4838-b823-5a88fe39fd0c" /&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,0c45f600-d3fb-4838-b823-5a88fe39fd0c.aspx</comments>
      <category>.NET</category>
      <category>C#</category>
      <category>Developer Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=c50452f9-765e-46ad-8f50-f44d13da7a7b</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,c50452f9-765e-46ad-8f50-f44d13da7a7b.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,c50452f9-765e-46ad-8f50-f44d13da7a7b.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c50452f9-765e-46ad-8f50-f44d13da7a7b</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This was an interesting issue I ran into today. We've got a utility I wrote which
can search Outlook MSG files from a desktop interface. As part of the program you
can print the results to a PDF - I'm using Crystal Reports to do the printing. We
had this application installed on a desktop machine for a while but decided to move
it over to one of our servers which had a lot more hard drive space. After moving
it, when we attempted to print we'd get the error: 
</p>
        <p>
"An error has occurred while attempting to load the Crystal Reports runtime" 
</p>
        <p>
At first I thought it might be related to needing the CR DLL's installed instead of
just being deployed in the app's directory. We installed them and tried again - same
exception. Further down in the error (which was actually helpful - imagine that!),
"Please install the appropriate Crystal Reports redistributable (snip) containing
the correct version of the Crystal Reports runtime (x86, x64, or Itanium).
</p>
        <p>
Hmm...x86 vs x64 - that has to be it - this was Windows 2003 Server (64 bit) vs. XP.
I actually just recently listened to a <a href="http://www.dotnetrocks.com" target="_blank">DotNetRocks</a> podcast
which talked about .NET applications running under a 64 bit OS. They mentioned that,
by default, most .NET applications are compiled under "Any CPU". That means the code
get's JIT'ed to 64 bit code under a 64 bit OS - sounds OK. The only catch is that
all the components must also be compiled the same way, otherwise you run into problems.
I didn't really want to have two different sets of DLL's so I went back into my application
and changed it from "Any CPU" to x86 code and recompiled. Order was restored to the
universe. 
</p>
        <p>
          <strong>Links: </strong>
        </p>
        <p>
          <a href="http://www.dotnetrocks.com">http://www.dotnetrocks.com</a>
        </p>
        <img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=c50452f9-765e-46ad-8f50-f44d13da7a7b" />
      </body>
      <title>Strange Crystal Reports Issue</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,c50452f9-765e-46ad-8f50-f44d13da7a7b.aspx</guid>
      <link>http://www.rcs-solutions.com/blog/2008/08/06/StrangeCrystalReportsIssue.aspx</link>
      <pubDate>Wed, 06 Aug 2008 00:48:19 GMT</pubDate>
      <description>&lt;p&gt;
This was an interesting issue I ran into today. We've got a utility I wrote which
can search Outlook MSG files from a desktop interface. As part of the program you
can print the results to a PDF - I'm using Crystal Reports to do the printing. We
had this application installed on a desktop machine for a while but decided to move
it over to one of our servers which had a lot more hard drive space. After moving
it, when we attempted to print we'd get the error: 
&lt;/p&gt;
&lt;p&gt;
"An error has occurred while attempting to load the Crystal Reports runtime" 
&lt;/p&gt;
&lt;p&gt;
At first I thought it might be related to needing the CR DLL's installed instead of
just being deployed in the app's directory. We installed them and tried again - same
exception. Further down in the error (which was actually helpful - imagine that!),
"Please install the appropriate Crystal Reports redistributable (snip) containing
the correct version of the Crystal Reports runtime (x86, x64, or Itanium).
&lt;/p&gt;
&lt;p&gt;
Hmm...x86 vs x64 - that has to be it - this was Windows 2003 Server (64 bit) vs. XP.
I actually just recently listened to a &lt;a href="http://www.dotnetrocks.com" target="_blank"&gt;DotNetRocks&lt;/a&gt; podcast
which talked about .NET applications running under a 64 bit OS. They mentioned that,
by default, most .NET applications are compiled under "Any CPU". That means the code
get's JIT'ed to 64 bit code under a 64 bit OS - sounds OK. The only catch is that
all the components must also be compiled the same way, otherwise you run into problems.
I didn't really want to have two different sets of DLL's so I went back into my application
and changed it from "Any CPU" to x86 code and recompiled. Order was restored to the
universe. 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Links: &lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.dotnetrocks.com"&gt;http://www.dotnetrocks.com&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=c50452f9-765e-46ad-8f50-f44d13da7a7b" /&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,c50452f9-765e-46ad-8f50-f44d13da7a7b.aspx</comments>
      <category>.NET</category>
    </item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=f209f8c4-6087-41cb-b876-ff349f42e8e2</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,f209f8c4-6087-41cb-b876-ff349f42e8e2.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,f209f8c4-6087-41cb-b876-ff349f42e8e2.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=f209f8c4-6087-41cb-b876-ff349f42e8e2</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I mentioned Dependency Injection / Inversion of Control (DI/IoC) recently and I really
didn't explain what it is, why you might want to use this particular pattern, and
why on earth you'd need a framework for it. It's a fancy name for a fairly simple
concept. Instead of creating objects inside of your classes, you let the calling code
"inject" the necessary instances into your code. It's probably easiest to see this
in some code. I'm going to show both C# and VFP code, since I don't want you to get
the idea that this is a .NET-only type thing. 
<br />
 
</p>
        <div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new">
          <p style="margin: 0px">
            <span style="color: #2b91af">   1</span> <span style="color: blue">public</span><span style="color: blue">class</span><span style="color: #2b91af">SampleDependency</span></p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   2</span> {
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   3</span>    <span style="color: blue">public</span><span style="color: blue">string</span> SayHello()
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   4</span>    {
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   5</span>       <span style="color: blue">return</span><span style="background: #e5e5e5">"Hello"</span>;
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   6</span>    }
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   7</span> }
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   8</span> 
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   9</span> <span style="color: blue">public</span><span style="color: blue">class</span><span style="color: #2b91af">Sample</span></p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   10</span> {
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   11</span>    <span style="color: blue">protected</span><span style="color: #2b91af">SampleDependency</span> m_depend;
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   12</span> 
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   13</span>    <span style="color: blue">public</span><span style="color: #2b91af">SampleDependency</span> Depend
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   14</span>    {
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   15</span>       <span style="color: blue">set</span> { <span style="color: blue">this</span>.m_depend
= <span style="color: blue">value</span>; }
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   16</span>    }
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   17</span> 
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   18</span>    <span style="color: blue">public</span> Sample(<span style="color: #2b91af">SampleDependency</span> depend)
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   19</span>    {
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   20</span>      
m_depend = depend;
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   21</span>    }
</p>
          <p style="margin: 0px">
            <span style="color: #2b91af">   22</span> }
</p>
          <p style="margin: 0px">
 
</p>
        </div>
        <div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new">
          <p style="margin: 0px">
            <span style="color: #2b91af">  </span>    <span style="color: #2b91af">Sample</span> sample
= <span style="color: blue">new</span><span style="color: #2b91af">Sample</span>(<span style="color: blue">new</span><span style="color: #2b91af">SampleDependency</span>());
</p>
          <p style="margin: 0px">
 
</p>
        </div>
        <b>VFP Version</b>
        <pre style="background: #eeeeee">DEFINE CLASS SampleDependency AS Session 
   FUNCTION SayHello() 
      RETURN "Hello" 
   ENDFUNC 
ENDDEFINE 

DEFINE CLASS Sample AS Session 
   oDepend = NULL 
   FUNCTION Init(toDepend) 
      This.oDepend = toDepend 
   ENDFUNC 
ENDDEFINE 

loSample = CREATEOBJECT("Sample", CREATEOBJECT("SampleDependency"))</pre>
        <pre>
        </pre>
        <p>
Notice that in both cases, we are passing in the instance we want the class to use
instead of letting the class create the instance itself. That's all DI/IoC is. Honest,
that's it. This is DI via a constructor (you can also do it via a property setting
instead; notice in the sample C# code I created a write-only property which could
hold the reference). 
</p>
        <p>
So the next obvious question is, why? What's wrong with just creating the object inside
of the class? 
</p>
        <p>
One thing DI gives you is the ability to easily swap in different objects. In the
C# example, we probably would change the parameter from a specific type to an interface.
Now any class which implements that interface can be injected into this class. In
VFP, since it's not strongly typed, you can just pass in whatever instance you'd like
(it's up to you to make sure it doesn't blow up at runtime by accessing some method
or property which isn't on the passed in object). My initial thought after seeing
this was, well, can't I just use an abstract factory pattern instead? In an abstract
factory you delegate object creation to a "object factory" - usually passing in a
name or calling a method which returns the actual instance you'd like to use. This
sounds like almost the same thing. 
</p>
        <p>
An abstract factory does let you do that, but it doesn't let you easily do something
the DI/IoC pattern does: test your objects. Let's suppose you want to write a test
for a class which uses another class to send out an e-mail. You aren't really trying
to test sending an e-mail - that's just one of the things the class you're testing
happens to do during some process. In fact, you really don't want to send out an e-mail;
we don't want to spam our users. If you happen to use the abstract factory pattern,
you would need to modify it to create your <a href="http://weblogs.asp.net/rosherove/archive/2007/09/16/mocks-and-stubs-the-difference-is-in-the-flow-of-information.aspx" target="_blank">dummy/stub/mock</a> object
for sending an e-mail (in VFP that's most likely by editing a record in a table, but
the idea is the same), then test the object in question. If you used the DI/IoC pattern
the only thing you need to do is pass in your dummy/stub/mock object. No other modifications
are necessary. 
</p>
        <p>
OK, so this all looks simple enough. Why would you need a framework for the above?!
One of the biggest reasons - less typing. You'll notice that in order to use any of
these objects you may have to pass in a bunch of other dependency objects (which themselves
may have other dependencies). For a complex set of objects that could really suck.
A DI framework does that for you along with the benefits of an abstract factory, all
rolled up into one. In your code you call the DI framework and tell it to get you
an instance of a class - it figures out what objects need to be passed in for you
so you don't need to do it. In your tests, you can instanciate the objects directly
and pass in your stub/dummy/mock objects instead. 
</p>
        <p>
          <strong>Links:</strong>
        </p>
        <p>
          <a href="http://weblogs.asp.net/rosherove/archive/2007/09/16/mocks-and-stubs-the-difference-is-in-the-flow-of-information.aspx">http://weblogs.asp.net/rosherove/archive/2007/09/16/mocks-and-stubs-the-difference-is-in-the-flow-of-information.aspx</a>
          <br />
          <a title="http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx" href="http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx">http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx</a>
        </p>
        <img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=f209f8c4-6087-41cb-b876-ff349f42e8e2" />
      </body>
      <title>What is Dependency Injection?</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,f209f8c4-6087-41cb-b876-ff349f42e8e2.aspx</guid>
      <link>http://www.rcs-solutions.com/blog/2008/07/12/WhatIsDependencyInjection.aspx</link>
      <pubDate>Sat, 12 Jul 2008 14:34:13 GMT</pubDate>
      <description>&lt;p&gt;
I mentioned Dependency Injection / Inversion of Control (DI/IoC) recently and I really
didn't explain what it is, why you might want to use this particular pattern, and
why on earth you'd need a framework for it. It's a fancy name for a fairly simple
concept. Instead of creating objects inside of your classes, you let the calling code
"inject" the necessary instances into your code. It's probably easiest to see this
in some code. I'm going to show both C# and VFP code, since I don't want you to get
the idea that this is a .NET-only type thing. 
&lt;br&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 1&lt;/span&gt;&amp;nbsp;&lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af"&gt;SampleDependency&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 2&lt;/span&gt; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 3&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;string&lt;/span&gt; SayHello()
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 4&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 5&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;return&lt;/span&gt; &lt;span style="background: #e5e5e5"&gt;"Hello"&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 6&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 7&lt;/span&gt; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 8&lt;/span&gt;&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 9&lt;/span&gt;&amp;nbsp;&lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Sample&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 10&lt;/span&gt; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 11&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;protected&lt;/span&gt; &lt;span style="color: #2b91af"&gt;SampleDependency&lt;/span&gt; m_depend;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 12&lt;/span&gt;&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 13&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: #2b91af"&gt;SampleDependency&lt;/span&gt; Depend
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 14&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 15&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;set&lt;/span&gt; { &lt;span style="color: blue"&gt;this&lt;/span&gt;.m_depend
= &lt;span style="color: blue"&gt;value&lt;/span&gt;; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 16&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 17&lt;/span&gt;&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 18&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;public&lt;/span&gt; Sample(&lt;span style="color: #2b91af"&gt;SampleDependency&lt;/span&gt; depend)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 19&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 20&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
m_depend = depend;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 21&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp;&amp;nbsp; 22&lt;/span&gt; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;/div&gt;
&lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;&amp;nbsp; &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;Sample&lt;/span&gt; sample
= &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Sample&lt;/span&gt;(&lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;SampleDependency&lt;/span&gt;());
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;/div&gt;
&lt;b&gt;VFP Version&lt;/b&gt;&lt;pre style="background: #eeeeee"&gt;DEFINE CLASS SampleDependency AS Session 
   FUNCTION SayHello() 
      RETURN "Hello" 
   ENDFUNC 
ENDDEFINE 

DEFINE CLASS Sample AS Session 
   oDepend = NULL 
   FUNCTION Init(toDepend) 
      This.oDepend = toDepend 
   ENDFUNC 
ENDDEFINE 

loSample = CREATEOBJECT("Sample", CREATEOBJECT("SampleDependency"))&lt;/pre&gt;
&lt;pre&gt; 
&lt;/pre&gt;
&lt;p&gt;
Notice that in both cases, we are passing in the instance we want the class to use
instead of letting the class create the instance itself. That's all DI/IoC is. Honest,
that's it. This is DI via a constructor (you can also do it via a property setting
instead; notice in the sample C# code I created a write-only property which could
hold the reference). 
&lt;/p&gt;
&lt;p&gt;
So the next obvious question is, why? What's wrong with just creating the object inside
of the class? 
&lt;/p&gt;
&lt;p&gt;
One thing DI gives you is the ability to easily swap in different objects. In the
C# example, we probably would change the parameter from a specific type to an interface.
Now any class which implements that interface can be injected into this class. In
VFP, since it's not strongly typed, you can just pass in whatever instance you'd like
(it's up to you to make sure it doesn't blow up at runtime by accessing some method
or property which isn't on the passed in object). My initial thought after seeing
this was, well, can't I just use an abstract factory pattern instead? In an abstract
factory you delegate object creation to a "object factory" - usually passing in a
name or calling a method which returns the actual instance you'd like to use. This
sounds like almost the same thing. 
&lt;/p&gt;
&lt;p&gt;
An abstract factory does let you do that, but it doesn't let you easily do something
the DI/IoC pattern does: test your objects. Let's suppose you want to write a test
for a class which uses another class to send out an e-mail. You aren't really trying
to test sending an e-mail - that's just one of the things the class you're testing
happens to do during some process. In fact, you really don't want to send out an e-mail;
we don't want to spam our users. If you happen to use the abstract factory pattern,
you would need to modify it to create your &lt;a href="http://weblogs.asp.net/rosherove/archive/2007/09/16/mocks-and-stubs-the-difference-is-in-the-flow-of-information.aspx" target="_blank"&gt;dummy/stub/mock&lt;/a&gt; object
for sending an e-mail (in VFP that's most likely by editing a record in a table, but
the idea is the same), then test the object in question. If you used the DI/IoC pattern
the only thing you need to do is pass in your dummy/stub/mock object. No other modifications
are necessary. 
&lt;/p&gt;
&lt;p&gt;
OK, so this all looks simple enough. Why would you need a framework for the above?!
One of the biggest reasons - less typing. You'll notice that in order to use any of
these objects you may have to pass in a bunch of other dependency objects (which themselves
may have other dependencies). For a complex set of objects that could really suck.
A DI framework does that for you along with the benefits of an abstract factory, all
rolled up into one. In your code you call the DI framework and tell it to get you
an instance of a class - it figures out what objects need to be passed in for you
so you don't need to do it. In your tests, you can instanciate the objects directly
and pass in your stub/dummy/mock objects instead. 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Links:&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://weblogs.asp.net/rosherove/archive/2007/09/16/mocks-and-stubs-the-difference-is-in-the-flow-of-information.aspx"&gt;http://weblogs.asp.net/rosherove/archive/2007/09/16/mocks-and-stubs-the-difference-is-in-the-flow-of-information.aspx&lt;/a&gt;
&lt;br&gt;
&lt;a title="http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx" href="http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx"&gt;http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=f209f8c4-6087-41cb-b876-ff349f42e8e2" /&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,f209f8c4-6087-41cb-b876-ff349f42e8e2.aspx</comments>
      <category>.NET</category>
      <category>Software</category>
      <category>VFP</category>
    </item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=25546f15-666b-4ef6-8c95-6f002f77732f</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,25546f15-666b-4ef6-8c95-6f002f77732f.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,25546f15-666b-4ef6-8c95-6f002f77732f.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=25546f15-666b-4ef6-8c95-6f002f77732f</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I attended a <a href="http://www.dayofdotnet.org/Lansing/2008/" target="_blank">Day
of Dot Net</a> event in Lansing a few week back. If you're not familiar with them,
they are free mini-conferences (one day) about, not surprisingly, .NET. 
</p>
        <p>
I had originally planned on driving out to it Saturday morning, but then Jenn pointed
out I'd have to get up really early to get there around 8am. I already work in Farmington,
which is 45 minutes to 1 hour from home (and 45 minutes to 1 hour closer to Lansing)
and would end up being a really long day for me. So I ended up just staying at a hotel
in Lansing Friday night. That turned out to be a great idea. Note to self: the Best
Western in Lansing feels and smells like a 80's style bowling alley.
</p>
        <p>
When I got to the hotel, I had some time to look up directions to the college where
it was being held. It was only a few miles away, so I decided to not bother to drive
over there on Friday night (which is what I would normally have done). In the morning
I followed the directions Google Maps had given and found myself in a church parking
lot (hmm..."Day of Dot Net and Evangelical Revival??"). I checked the map a few times
and it looked OK, and I was exactly where it said I should be. I think that was about
the point where I starting cursing out Google maps. I had left all my information
about the conference in the trunk so I had to get out of the car to get at it. I happened
to notice that the road I was on looked like it actually continued around the side
of the church (imagine a light bulb going off above my head: "hey...maybe...."). I
jumped back in the car and drove around the parking lot and sure enough, the trees
suddenly cleared on my left hand side where the college was hiding. I noticed another
car stop right about where I stopped, so it wasn't just me being dense (honest!).
Note to organizers - great event, but a small sign would have been appreciated. 
</p>
        <p>
When I got into the building (which also wasn't marked, so I still wasn't entirely
sure I was at the right entrance), I was surprised at how few people were there -
that kind of surprised me since I wasn't able to make it to the last DoDN because
it had filled up. It turns out that as the morning wore on the sessions really started
to fill up. 
</p>
        <p>
The sessions were an hour long - which is REALLY short; they flew by. The sessions
all seemed to run a few minutes long which pushed into the next session running a
bit longer. The lunch break helped to reset everything. 
</p>
        <p>
A few notes to the various presenters:
</p>
        <ul>
          <li>
The bottom 1/3 of the screen really isn't visible if you're sitting in the back of
the room. I was sitting in the second row and couldn't read some of it. 
</li>
          <li>
White text on a black background might be easier on your eyes for development, but
it's impossible to read when it's projected up on a screen. I'd suggest sticking with
black text on a white background. 
</li>
          <li>
Don't try to wing demo's. Only a few people can successfully pull that off - you're
probably not one of them. 
</li>
        </ul>
        <p>
I actually ran into a few people I knew - one was someone from the local VFP user
group, the other was a old-VFP developer that I haven't seen in a few years. That
was a nice surprise. Overall, I was impressed by the number of people who attended,
considering you're basically giving up a weekend day to attend. It's nice to see that
some people actually care about getting better as developers (either that or they,
like me, needed a few new shirts for their wardrobe).
</p>
        <p>
One session happened to stand out in my mind - a session about Dependency Injection
/ Inversion of Control (specifically, the Windsor framework) by <a href="http://jrwren.wrenfam.com/blog/" target="_blank">Jay
Wren</a>. Well organized, hit every question I had about DI/IoC. Honestly, I didn't
"get" DI/IoC before this session; yeah, I understood what it was, but not really why
on earth I might need a framework for it. It is actually an elegant way of solving
a particular development problem, giving you the benefits of a factory pattern and
the flexibility of DI, without getting in your way (at least that's what my notes
say). I had the "a ha!" moment, then promptly lost it in one of the other sessions.
I'm sure it will come to me at some point, although at this point I'm getting a bit
nervous ;-)
</p>
        <p>
At the end of the conference, they ended up giving away of ton of stuff. Just not
to me. Oh well, maybe next time.
</p>
        <p>
Overall, I definitely attend another one - a big thanks to the organizers and presenters
and sponsors, I know it's a lot of work to put something like this on - it was appreciated.
Just try to make sure you've got some soft drinks (Coke, Mt. Dew, etc.) available
in the morning next time around &lt;g&gt;. It's hard for some of us to get moving
in the morning without some caffeine (for us non-coffee drinkers). Sure I feel all
healthy from the orange juice I ended up drinking, but it didn't help much to put
a spring in my step.
</p>
        <p>
          <strong>Links</strong>
        </p>
        <p>
          <a href="http://www.dayofdotnet.org/Lansing/2008/" target="_blank">http://www.dayofdotnet.org/Lansing/2008/</a>
          <br />
          <a href="http://jrwren.wrenfam.com/blog/" target="_blank">http://jrwren.wrenfam.com/blog/</a>
        </p>
        <img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=25546f15-666b-4ef6-8c95-6f002f77732f" />
      </body>
      <title>Day of .NET (Lansing)</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,25546f15-666b-4ef6-8c95-6f002f77732f.aspx</guid>
      <link>http://www.rcs-solutions.com/blog/2008/07/06/DayOfNETLansing.aspx</link>
      <pubDate>Sun, 06 Jul 2008 16:24:59 GMT</pubDate>
      <description>&lt;p&gt;
I attended a &lt;a href="http://www.dayofdotnet.org/Lansing/2008/" target="_blank"&gt;Day
of Dot Net&lt;/a&gt; event in Lansing a few week back. If you're not familiar with them,
they are free mini-conferences (one day) about, not surprisingly, .NET. 
&lt;/p&gt;
&lt;p&gt;
I had originally planned on driving out to it Saturday morning, but then Jenn pointed
out I'd have to get up really early to get there around 8am. I already work in Farmington,
which is 45 minutes to 1 hour from home (and 45 minutes to 1 hour closer to Lansing)
and would end up being a really long day for me. So I ended up just staying at a hotel
in Lansing Friday night. That turned out to be a great idea. Note to self: the Best
Western in Lansing feels and smells like a 80's style bowling alley.
&lt;/p&gt;
&lt;p&gt;
When I got to the hotel, I had some time to look up directions to the college where
it was being held. It was only a few miles away, so I decided to not bother to drive
over there on Friday night (which is what I would normally have done). In the morning
I followed the directions Google Maps had given and found myself in a church parking
lot (hmm..."Day of Dot Net and Evangelical Revival??"). I checked the map a few times
and it looked OK, and I was exactly where it said I should be. I think that was about
the point where I starting cursing out Google maps. I had left all my information
about the conference in the trunk so I had to get out of the car to get at it. I happened
to notice that the road I was on looked like it actually continued around the side
of the church (imagine a light bulb going off above my head: "hey...maybe...."). I
jumped back in the car and drove around the parking lot and sure enough, the trees
suddenly cleared on my left hand side where the college was hiding. I noticed another
car stop right about where I stopped, so it wasn't just me being dense (honest!).
Note to organizers - great event, but a small sign would have been appreciated. 
&lt;/p&gt;
&lt;p&gt;
When I got into the building (which also wasn't marked, so I still wasn't entirely
sure I was at the right entrance), I was surprised at how few people were there -
that kind of surprised me since I wasn't able to make it to the last DoDN because
it had filled up. It turns out that as the morning wore on the sessions really started
to fill up. 
&lt;/p&gt;
&lt;p&gt;
The sessions were an hour long - which is REALLY short; they flew by. The sessions
all seemed to run a few minutes long which pushed into the next session running a
bit longer. The lunch break helped to reset everything. 
&lt;/p&gt;
&lt;p&gt;
A few notes to the various presenters:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
The bottom 1/3 of the screen really isn't visible if you're sitting in the back of
the room. I was sitting in the second row and couldn't read some of it. 
&lt;li&gt;
White text on a black background might be easier on your eyes for development, but
it's impossible to read when it's projected up on a screen. I'd suggest sticking with
black text on a white background. 
&lt;li&gt;
Don't try to wing demo's. Only a few people can successfully pull that off - you're
probably not one of them. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
I actually ran into a few people I knew - one was someone from the local VFP user
group, the other was a old-VFP developer that I haven't seen in a few years. That
was a nice surprise. Overall, I was impressed by the number of people who attended,
considering you're basically giving up a weekend day to attend. It's nice to see that
some people actually care about getting better as developers (either that or they,
like me, needed a few new shirts for their wardrobe).
&lt;/p&gt;
&lt;p&gt;
One session happened to stand out in my mind - a session about Dependency Injection
/ Inversion of Control (specifically, the Windsor framework) by &lt;a href="http://jrwren.wrenfam.com/blog/" target="_blank"&gt;Jay
Wren&lt;/a&gt;. Well organized, hit every question I had about DI/IoC. Honestly, I didn't
"get" DI/IoC before this session; yeah, I understood what it was, but not really why
on earth I might need a framework for it. It is actually an elegant way of solving
a particular development problem, giving you the benefits of a factory pattern and
the flexibility of DI, without getting in your way (at least that's what my notes
say). I had the "a ha!" moment, then promptly lost it in one of the other sessions.
I'm sure it will come to me at some point, although at this point I'm getting a bit
nervous ;-)
&lt;/p&gt;
&lt;p&gt;
At the end of the conference, they ended up giving away of ton of stuff. Just not
to me. Oh well, maybe next time.
&lt;/p&gt;
&lt;p&gt;
Overall, I definitely attend another one - a big thanks to the organizers and presenters
and sponsors, I know it's a lot of work to put something like this on - it was appreciated.
Just try to make sure you've got some soft drinks (Coke, Mt. Dew, etc.) available
in the morning next time around &amp;lt;g&amp;gt;. It's hard for some of us to get moving
in the morning without some caffeine (for us non-coffee drinkers). Sure I feel all
healthy from the orange juice I ended up drinking, but it didn't help much to put
a spring in my step.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Links&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.dayofdotnet.org/Lansing/2008/" target="_blank"&gt;http://www.dayofdotnet.org/Lansing/2008/&lt;/a&gt;
&lt;br&gt;
&lt;a href="http://jrwren.wrenfam.com/blog/" target="_blank"&gt;http://jrwren.wrenfam.com/blog/&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=25546f15-666b-4ef6-8c95-6f002f77732f" /&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,25546f15-666b-4ef6-8c95-6f002f77732f.aspx</comments>
      <category>.NET</category>
      <category>Conference</category>
    </item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=25ee2028-e0c6-47a6-8c07-da492b2213b3</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,25ee2028-e0c6-47a6-8c07-da492b2213b3.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,25ee2028-e0c6-47a6-8c07-da492b2213b3.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=25ee2028-e0c6-47a6-8c07-da492b2213b3</wfw:commentRss>
      <slash:comments>13</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I've been spending a lot of time lately doing some winter cleaning. We're trying to
free up some space in the basement for a play area for Brendan. It's amazing how much
stuff you can collect. We've thrown away a LOT of stuff - I'm pretty sure the garbage
guys hate us by now. Jenn mentioned that one of them didn't look too pleased when
he tried to lift one of the bags we put out. We've been donating anything with think
might still be useful, and we have people who drive through our subdivision on garbage
days looking for interesting finds. More power to them, I say; I'd rather someone
finds some use for this stuff instead of throwing it out. Besides, who's got the patience
for a garage sale? And who really wants to deal with people trying to get half price
for an item marked $1 that originally cost $50.
</p>
        <p>
Since I've been involved with computers for quite some time (and not all of it as
a developer), I've managed to collect quite a collection of old computers. Old Pentiums,
486's, a few 386's, motherboards, cases, power supplies, an unbelievable amount of
cables, network cards, video cards, etc. I'm planning on posting that stuff on our
local <a href="http://www.freecycle.org">freecycle</a> site to see if anyone might
be interested in it before tossing it. One of my regrets with a lot of this is that
I didn't give it away sooner, while it still may have been of more use to someone.
I guess that may have been why I kept it.
</p>
        <p>
A big part of this collection is a ton of books and magazines. I've whittled the magazines
down to something manageable, but I still have way too many books. I'm sure I'll add
more to the list as soon as I can convince myself that I really don't need them anymore,
and once I have time to go through the ones still hiding in the basement (and hopefully
before some of them aren't useful anymore). Here's a list of what's on the chopping
block (you might be surprised; there are some good books here):
</p>
        <ul>
          <li>
            <em>Apple II Plus/IIe Troubleshooting &amp; Repair Guide</em>, Robert C. Brenner.
Sams. ISBN: 0-672-22353-8 
</li>
          <li>
            <em>DNS and BIND 3rd Edition</em>, Paul Albitz &amp; Cricket Liu. O'Reilly. ISBN:
1-56592-512-2 
</li>
          <li>
            <strike>
              <em>XML Extensible Markup Language</em> (w/CD), Elliotte Rusty Harold. IDG
Books. ISBN: 0-7645-3199-9 </strike>
          </li>
          <li>
            <strike>
              <em>The Unified Modeling Language User Guide</em>, Booch, Rumbaugh, Jacobson.
Addison-Wesley. ISBN: 0-201-57168-4 </strike>
          </li>
          <li>
            <em>The Visual FoxPro 3 Codebook</em> (CD is missing), Yair Aan Griver. Sybex. ISBN:
0-7821-1648-5 
</li>
          <li>
            <strike>
              <em>Object Orientation in Visual Foxpro</em>, Savannah Brentnall. Addison-Wesley.
ISBN: 0-201-47943-5</strike>
          </li>
          <li>
            <strike>
              <em>Object Models: Strategies, Patterns, &amp; Applications (Second Edition)</em>,
Coad, North, Mayfield. Yourdon Press. ISBN: 0-13-840117-9</strike>
          </li>
          <li>
            <em>Visual Basic 6 Business Objects</em>, Rockford Lhotka. Wrox. ISBN: 1-861001-07-X 
</li>
          <li>
            <strike>
              <em>ASP.NET 2.0 Unleashed</em>, Stephen Walther. Sams. ISBN: 0-672-32823-2</strike>
          </li>
          <li>
            <strike>
              <em>Hacker's Guide to Visual FoxPro 6.0</em>, Granor, Roche. Hentzenwerke
Publishing. ISBN: 0-96550-936-2 </strike>
          </li>
          <li>
            <strike>
              <em>The Inmates Are Running The Asylum</em>, Alan Cooper. Sams. ISBN: 0-672-31649-8 </strike>
          </li>
          <li>
            <strike>
              <em>About Face: The Essentials of User Interface Design</em>, Alan Cooper.
IDG Books. ISBN: 1-56884-322-4 </strike>
          </li>
          <li>
            <strike>
              <em>The Improvement Guide</em>, Langley, Nolan, Nolan, Normal, Provost. Jossey-Bass.
ISBN: 0-7879-0257-8 </strike>
          </li>
          <li>
            <strike>
              <em>HTML: The Complete Reference (Second Edition)</em>, Thomas A. Powell.
Osborne. ISBN: 0-07-211977-2 </strike>
          </li>
          <li>
            <em>Effective Techniques for Application Development w/VFP 6.0</em>, Booth, Sawyer.
Hentzenwerke. ISBN: 0-96550-937-0 
</li>
          <li>
            <strike>
              <em>What's New in Visual FoxPro 8.0</em>, Granor, Hennig. Hentzenwerke. ISBN:
1-930919-40-9 </strike>
          </li>
          <li>
            <strike>
              <em>CrysDev: A Developer's Guide to Integrating Crystal Reports</em>, Craig
Berntson. Hentzenwerke. ISBN: 1-930919-38-7 </strike>
          </li>
          <li>
            <strike>
              <em>Advanced Object Oriented Programming w/VFP 6</em>, Egger.  Hentzenwerke.
ISBN: 0-96550-938-9 </strike>
          </li>
          <li>
            <strike>
              <em>Client/Server Applications w/VFP &amp; SQL Server</em>, Urwiler, DeWitt,
Ley, Koorhan. Hentzenwerke. ISBN: 1-930919-01-8 </strike>
          </li>
          <li>
            <strike>
              <em>C# Unleashed</em>, Joseph Mayo. Sams. ISBN: 0-672-321-22-X</strike>
          </li>
          <li>
            <strike>
              <em>Measuring and Managing Performance in Organizations</em>, Robert D. Austin.
Dorset House. ISBN: 0-932633-36-6</strike>
          </li>
          <li>
            <strike>
              <em>Windows 2000 Server Resource Kit (No CD)</em>, 8 books total<br /></strike> </li>
        </ul>
        <p>
If anyone might be interested in this stuff (books or computer techno-rubble), drop
me a line (I can take a pic. of the computer stuff). All of it free as long as you
pick up the shipping cost. I hope I don't regret giving away some of this, these books
have served me well &lt;g&gt;
</p>
        <p>
 
</p>
        <p>
          <strong>Links:</strong>
        </p>
        <p>
          <a title="http://www.freecycle.org" href="http://www.freecycle.org">http://www.freecycle.org</a>
        </p>
        <img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=25ee2028-e0c6-47a6-8c07-da492b2213b3" />
      </body>
      <title>Winter Cleaning</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,25ee2028-e0c6-47a6-8c07-da492b2213b3.aspx</guid>
      <link>http://www.rcs-solutions.com/blog/2007/12/13/WinterCleaning.aspx</link>
      <pubDate>Thu, 13 Dec 2007 03:23:03 GMT</pubDate>
      <description>&lt;p&gt;
I've been spending a lot of time lately doing some winter cleaning. We're trying to
free up some space in the basement for a play area for Brendan. It's amazing how much
stuff you can collect. We've thrown away a LOT of stuff - I'm pretty sure the garbage
guys hate us by now. Jenn mentioned that one of them didn't look too pleased when
he tried to lift one of the bags we put out. We've been donating anything with think
might still be useful, and we have people who drive through our subdivision on garbage
days looking for interesting finds. More power to them, I say; I'd rather someone
finds some use for this stuff instead of throwing it out. Besides, who's got the patience
for a garage sale? And who really wants to deal with people trying to get half price
for an item marked $1 that originally cost $50.
&lt;/p&gt;
&lt;p&gt;
Since I've been involved with computers for quite some time (and not all of it as
a developer), I've managed to collect quite a collection of old computers. Old Pentiums,
486's, a few 386's, motherboards, cases, power supplies, an unbelievable amount of
cables, network cards, video cards, etc. I'm planning on posting that stuff on our
local &lt;a href="http://www.freecycle.org"&gt;freecycle&lt;/a&gt; site to see if anyone might
be interested in it before tossing it. One of my regrets with a lot of this is that
I didn't give it away sooner, while it still may have been of more use to someone.
I guess that may have been why I kept it.
&lt;/p&gt;
&lt;p&gt;
A big part of this collection is a ton of books and magazines. I've whittled the magazines
down to something manageable, but I still have way too many books. I'm sure I'll add
more to the list as soon as I can convince myself that I really don't need them anymore,
and once I have time to go through the ones still hiding in the basement (and hopefully
before some of them aren't useful anymore). Here's a list of what's on the chopping
block (you might be surprised; there are some good books here):
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Apple II Plus/IIe Troubleshooting &amp;amp; Repair Guide&lt;/em&gt;, Robert C. Brenner.
Sams. ISBN: 0-672-22353-8 
&lt;li&gt;
&lt;em&gt;DNS and BIND 3rd Edition&lt;/em&gt;, Paul Albitz &amp;amp; Cricket Liu. O'Reilly. ISBN:
1-56592-512-2 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;XML Extensible Markup Language&lt;/em&gt; (w/CD), Elliotte Rusty Harold. IDG
Books. ISBN: 0-7645-3199-9 &lt;/strike&gt; 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;The Unified Modeling Language User Guide&lt;/em&gt;, Booch, Rumbaugh, Jacobson.
Addison-Wesley. ISBN: 0-201-57168-4 &lt;/strike&gt; 
&lt;li&gt;
&lt;em&gt;The Visual FoxPro 3 Codebook&lt;/em&gt; (CD is missing), Yair Aan Griver. Sybex. ISBN:
0-7821-1648-5 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;Object Orientation in Visual Foxpro&lt;/em&gt;, Savannah Brentnall. Addison-Wesley.
ISBN: 0-201-47943-5&lt;/strike&gt; 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;Object Models: Strategies, Patterns, &amp;amp; Applications (Second Edition)&lt;/em&gt;,
Coad, North, Mayfield. Yourdon Press. ISBN: 0-13-840117-9&lt;/strike&gt; 
&lt;li&gt;
&lt;em&gt;Visual Basic 6 Business Objects&lt;/em&gt;, Rockford Lhotka. Wrox. ISBN: 1-861001-07-X 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;ASP.NET 2.0 Unleashed&lt;/em&gt;, Stephen Walther. Sams. ISBN: 0-672-32823-2&lt;/strike&gt; 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;Hacker's Guide to Visual FoxPro 6.0&lt;/em&gt;, Granor, Roche. Hentzenwerke
Publishing. ISBN: 0-96550-936-2 &lt;/strike&gt; 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;The Inmates Are Running The Asylum&lt;/em&gt;, Alan Cooper. Sams. ISBN: 0-672-31649-8 &lt;/strike&gt; 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;About Face: The Essentials of User Interface Design&lt;/em&gt;, Alan Cooper.
IDG Books. ISBN: 1-56884-322-4 &lt;/strike&gt; 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;The Improvement Guide&lt;/em&gt;, Langley, Nolan, Nolan, Normal, Provost. Jossey-Bass.
ISBN: 0-7879-0257-8 &lt;/strike&gt; 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;HTML: The Complete Reference (Second Edition)&lt;/em&gt;, Thomas A. Powell.
Osborne. ISBN: 0-07-211977-2 &lt;/strike&gt; 
&lt;li&gt;
&lt;em&gt;Effective Techniques for Application Development w/VFP 6.0&lt;/em&gt;, Booth, Sawyer.
Hentzenwerke. ISBN: 0-96550-937-0 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;What's New in Visual FoxPro 8.0&lt;/em&gt;, Granor, Hennig. Hentzenwerke. ISBN:
1-930919-40-9 &lt;/strike&gt; 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;CrysDev: A Developer's Guide to Integrating Crystal Reports&lt;/em&gt;, Craig
Berntson. Hentzenwerke. ISBN: 1-930919-38-7 &lt;/strike&gt; 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;Advanced Object Oriented Programming w/VFP 6&lt;/em&gt;, Egger.&amp;nbsp; Hentzenwerke.
ISBN: 0-96550-938-9 &lt;/strike&gt; 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;Client/Server Applications w/VFP &amp;amp; SQL Server&lt;/em&gt;, Urwiler, DeWitt,
Ley, Koorhan. Hentzenwerke. ISBN: 1-930919-01-8 &lt;/strike&gt; 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;C# Unleashed&lt;/em&gt;, Joseph Mayo. Sams. ISBN: 0-672-321-22-X&lt;/strike&gt; 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;Measuring and Managing Performance in Organizations&lt;/em&gt;, Robert D. Austin.
Dorset House. ISBN: 0-932633-36-6&lt;/strike&gt; 
&lt;li&gt;
&lt;strike&gt;&lt;em&gt;Windows 2000 Server Resource Kit (No CD)&lt;/em&gt;, 8 books total&lt;br&gt;
&lt;/strike&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
If anyone might be interested in this stuff (books or computer techno-rubble), drop
me a line (I can take a pic. of the computer stuff). All of it free as long as you
pick up the shipping cost. I hope I don't regret giving away some of this, these books
have served me well &amp;lt;g&amp;gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Links:&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a title="http://www.freecycle.org" href="http://www.freecycle.org"&gt;http://www.freecycle.org&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=25ee2028-e0c6-47a6-8c07-da492b2213b3" /&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,25ee2028-e0c6-47a6-8c07-da492b2213b3.aspx</comments>
      <category>.NET</category>
      <category>Other</category>
      <category>VFP</category>
    </item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=2c5c386e-ad07-4dbd-8c3b-37f1d20a42a5</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,2c5c386e-ad07-4dbd-8c3b-37f1d20a42a5.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,2c5c386e-ad07-4dbd-8c3b-37f1d20a42a5.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=2c5c386e-ad07-4dbd-8c3b-37f1d20a42a5</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
There is a ton of great .NET content available on the web; everything from simple
code snippets to full blown apps. I really appreciate that people put the time into
this stuff and make it available. But I have one request: would it kill you to include
the namespace references in your sample code? There are thousands of classes in .NET
- I hate having to try and figure out where these classes are hiding in order to get
my code to compile (esp. since I’m normally looking at this code because I'm not familiar
with the class or classes required to do whatever it is I'm trying to accomplish.
Having said that, I never realized VS would actually help resolve these references
for me. If you right-click on a type (in this case, I right-clicked on File), there
is a Resolve Namespace option on the content menu: 
</p>
        <p>
 
</p>
        <p>
          <a href="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/Codesamplesnotincludingnamespacereferenc_12E93/namespace_4.png">
            <img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="655" alt="namespace" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/Codesamplesnotincludingnamespacereferenc_12E93/namespace_thumb_1.png" width="549" border="0" />
          </a>
        </p>
Very nice!<img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=2c5c386e-ad07-4dbd-8c3b-37f1d20a42a5" /></body>
      <title>Code samples &amp;ndash; not including namespace references</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,2c5c386e-ad07-4dbd-8c3b-37f1d20a42a5.aspx</guid>
      <link>http://www.rcs-solutions.com/blog/2007/10/16/CodeSamplesNdashNotIncludingNamespaceReferences.aspx</link>
      <pubDate>Tue, 16 Oct 2007 01:31:13 GMT</pubDate>
      <description>&lt;p&gt;
There is a ton of great .NET content available on the web; everything from simple
code snippets to full blown apps. I really appreciate that people put the time into
this stuff and make it available. But I have one request: would it kill you to include
the namespace references in your sample code? There are thousands of classes in .NET
- I hate having to try and figure out where these classes are hiding in order to get
my code to compile (esp. since I’m normally looking at this code because I'm not familiar
with the class or classes required to do whatever it is I'm trying to accomplish.
Having said that, I never realized VS would actually help resolve these references
for me. If you right-click on a type (in this case, I right-clicked on File), there
is a Resolve Namespace option on the content menu: 
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/Codesamplesnotincludingnamespacereferenc_12E93/namespace_4.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="655" alt="namespace" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/Codesamplesnotincludingnamespacereferenc_12E93/namespace_thumb_1.png" width="549" border="0"&gt;&lt;/a&gt; 
&lt;/p&gt;
Very nice!&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=2c5c386e-ad07-4dbd-8c3b-37f1d20a42a5" /&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,2c5c386e-ad07-4dbd-8c3b-37f1d20a42a5.aspx</comments>
      <category>.NET</category>
    </item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=e16085ad-65fd-452f-bc88-c61c3fa507aa</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,e16085ad-65fd-452f-bc88-c61c3fa507aa.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,e16085ad-65fd-452f-bc88-c61c3fa507aa.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=e16085ad-65fd-452f-bc88-c61c3fa507aa</wfw:commentRss>
      <title>Truncating a string at word boundaries</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,e16085ad-65fd-452f-bc88-c61c3fa507aa.aspx</guid>
      <link>http://www.rcs-solutions.com/blog/2007/10/13/TruncatingAStringAtWordBoundaries.aspx</link>
      <pubDate>Sat, 13 Oct 2007 17:42:58 GMT</pubDate>
      <description>&lt;p&gt;
A while back I needed a routine which would display the first few hundred characters
of a longer chunk of text. Obviously, it's easy enough to do that with the Substring
method of a string. However, I wanted to do this on a word boundary (I didn't want
to end up with half of the word being displayed). So I wrote a simple routine which
broke up the string into an array (using Split()), then rebuilt the string (keeping
track of the length along the way). Maybe 25 lines or code or so. It seemed to work
OK, so I was good to go.
&lt;/p&gt;
&lt;p&gt;
The other day I realized I needed to adjust the code to strip out HTML markup before
displaying the text - you can imagine how "nice" that might look if I happened to
chop off an ending tag somewhere. I knew I had a third party library to do this; there
are a lot of really useful little routines hiding in the &lt;a href="http://www.west-wind.com/wwstore/item.aspx?sku=WEBSTOREDOTNET20"&gt;West
Wind Web Store .NET 2.0&lt;/a&gt;. So I took a look through the library and found what I
was looking for. While looking for it, I noticed another routine which appeared to
do exactly the same thing I wanted. Except it was like 5 lines and much easier to
understand. Doh! 
&lt;/p&gt;
&lt;p&gt;
30 seconds later I rewrote my routine. Here it is...
&lt;/p&gt;
&lt;p class="MsoNormal"&gt;
&lt;span style="font-size: 10pt; font-family: consolas"&gt;&amp;nbsp;&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;string&lt;/span&gt; TruncateString(&lt;span style="color: blue"&gt;string&lt;/span&gt; source, &lt;span style="color: blue"&gt;int&lt;/span&gt; maxLength, &lt;span style="color: blue"&gt;string&lt;/span&gt; ending)&lt;br&gt;
&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
{&lt;br&gt;
&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas"&gt;&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="background: yellow"&gt;&lt;?xml:namespace prefix = o /&gt;//
Do we even have to truncate it?&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p class="MsoNormal"&gt;
&lt;span style="font-size: 10pt; font-family: consolas"&gt;&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; (source.Length
&amp;lt;= maxLength)&lt;br&gt;
&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas"&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; source;&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p class="MsoNormal"&gt;
&lt;span style="font-size: 10pt; font-family: consolas"&gt;&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; text
= source.Substring(0, maxLength);&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p class="MsoNormal"&gt;
&lt;span style="font-size: 10pt; font-family: consolas"&gt;
&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p class="MsoNormal"&gt;
&lt;span style="font-size: 10pt; font-family: consolas"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
text = text.Substring(0, text.LastIndexOf(&lt;span style="background: white"&gt;" "&lt;/span&gt;));&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas"&gt;
&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;p class="MsoNormal"&gt;
&lt;span style="font-size: 10pt; font-family: consolas"&gt;&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; text;&lt;br&gt;
&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: consolas"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
}&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: 'Arial','sans-serif'"&gt;
&lt;o:p&gt;&lt;/o:p&gt;
&lt;/span&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=e16085ad-65fd-452f-bc88-c61c3fa507aa" /&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,e16085ad-65fd-452f-bc88-c61c3fa507aa.aspx</comments>
      <category>.NET</category>
    </item>
  </channel>
</rss>