<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>Paul Mrozowski's Blog</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>Sat, 27 Sep 2008 15:48:31 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.0.7226.0</generator>
    <managingEditor>paulm@rcs-solutions.com</managingEditor>
    <webMaster>paulm@rcs-solutions.com</webMaster>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/PaulMrozowski" type="application/rss+xml" /><item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=e3e63f03-3963-4c19-9409-ee67a531ed91</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,e3e63f03-3963-4c19-9409-ee67a531ed91.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,e3e63f03-3963-4c19-9409-ee67a531ed91.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=e3e63f03-3963-4c19-9409-ee67a531ed91</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <title>Recursive Queries in SQL Server 2005</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,e3e63f03-3963-4c19-9409-ee67a531ed91.aspx</guid>
      <link>http://feeds.feedburner.com/~r/PaulMrozowski/~3/404744291/RecursiveQueriesInSQLServer2005.aspx</link>
      <pubDate>Sat, 27 Sep 2008 15:48:31 GMT</pubDate>
      <description>&lt;style type="text/css"&gt;
pre { background-color: #efefef; font-family:consolas,courier new; }
&lt;/style&gt;
One of the really killer features included in SQL Server 2005 was Common Table Expressions.
One of the really nice uses for them is recursive queries. Imagine any kind of hierarchical
set of date (org. chart, security which allows nested roles, parts/assemblies, etc.).
You can use CTE's to walk up or down these trees to build it's result set. Let's look
at a simple example of this. I'm going to create a table named "ItemGroups" which
is nothing more than a listing of items which have a PK, Title, Description, and foreign
key to a parent it may be a child of. &lt;pre&gt;CREATE TABLE [dbo].[ItemGroups](
	[iid] [int] IDENTITY(1,1) NOT NULL,
	[Title] [varchar](60) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
	[Description] [text] COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
	[fk_ItemGroups] [int] NULL,
 CONSTRAINT [PK_ItemGroups] PRIMARY KEY CLUSTERED 
(
	[iid] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
&lt;/pre&gt;
&lt;p&gt;
Then, I'm going to add some sample data to this table:
&lt;/p&gt;
&lt;pre&gt;&lt;strong&gt;&lt;u&gt; iid Title Description fk_ItemGroups&lt;/u&gt;&lt;/strong&gt; 1 Root This is the
root NULL 2 Child 1 This is a child of root 1 3 Child 2 This is a child of root 1
4 Grandchild 1 This is a child of Child 1 2 5 Grandchild 2 This is a child of Child
2 3 6 Great Grandchild 1 This is a child of Grandchild 1 4 &lt;/pre&gt;
&lt;p&gt;
If we draw this out as a "tree", it would look something like this (note the modern
looking ASCII art...)
&lt;/p&gt;
&lt;pre&gt;- Root
  - Child 1
    - Grandchild 1
       - Great Grandchild 1
  - Child 2
    - Grandchild 2
&lt;/pre&gt;
&lt;p&gt;
OK, great - let's suppose we want to walk up or down this tree from a known starting
point. How might we use a CTE to do that?
&lt;/p&gt;
&lt;p&gt;
It might help to understand the basic format of a CTE:
&lt;/p&gt;
&lt;pre&gt;WITH SomeTableName (List of resulting fields)
(
   SELECT -- Starting point or anchor of the query
    UNION ALL
   SELECT -- Recursive portion of the query
)
SELECT -- Final select from SomeTableName
&lt;/pre&gt;
&lt;p&gt;
We have the "WITH" portion which describes what our CTE cursor would look like (we
can reference this in the recursive portion of the query and in the final SELECT).
Then we have the first SELECT which selects the starting record(s) for the recursive
portion of our query. It's basically the starting point. The second SELECT pulls in
matching records which are children or parents of the record in the anchor portion. 
&lt;/p&gt;
&lt;p&gt;
Let's see what that would look like against our table, assuming we want to walk down
the hierarchy - in this code, we're going to be starting with the root node.
&lt;/p&gt;
&lt;pre&gt;DECLARE @startNode int
SET @startNode = 1; -- Note the semicolon - it's required for the command
                    -- immediately before the CTE

WITH Items (iid, Title, Description, fk_ItemGroups) AS
( -- This is the 'Anchor' or starting point of the recursive query
  SELECT ig.iid,
         ig.Title, 
         ig.Description,
         ig.fk_ItemGroups
    FROM ItemGroups ig
   WHERE ig.iid = @startNode
   UNION ALL -- This is the recursive portion of the query
  SELECT ig.iid,
         ig.Title, 
         ig.Description,
         ig.fk_ItemGroups
    FROM ItemGroups ig
   INNER JOIN Items -- Note the reference to CTE table name
      ON ig.fk_ItemGroups = Items.iid
)
SELECT *
  FROM Items
&lt;/pre&gt;
&lt;p&gt;
If we run this, here's our results (notice that the query automatically stops recursing
when no more matches are found).
&lt;/p&gt;
&lt;pre&gt;&lt;strong&gt;&lt;u&gt; iid Title Description fk_ItemGroups&lt;/u&gt;&lt;/strong&gt; 1 Root This is the
root NULL 2 Child 1 This is a child of root 1 3 Child 2 This is a child of root 1
5 Grandchild 2 This is a child of Child 2 3 4 Grandchild 1 This is a child of Child
1 2 6 Great Grandchild 1 This is a child of Grandchild 1 4 &lt;/pre&gt;
&lt;p&gt;
If we change the starting node to 2 and rerun this, you'll see we only get Child 1
and it's children:
&lt;/p&gt;
&lt;pre&gt;2       Child 1                 This is a child of root         1
4       Grandchild 1            This is a child of Child 1      2
6       Great Grandchild 1      This is a child of Grandchild 1 4
&lt;/pre&gt;
&lt;p&gt;
And if we change it to start at Grandchild 1, we get:
&lt;/p&gt;
&lt;pre&gt;4       Grandchild 1            This is a child of Child 1      2
6       Great Grandchild 1      This is a child of Grandchild 1 4
&lt;/pre&gt;
&lt;p&gt;
What if we'd like to walk "up" the hierarchy instead? That's just as easy. In the
recursive portion of the query, we need to change our join condition. The first query
will return the record we want to start on (aliased as 'Item' in this example). To
walk up the chain, our fk_ItemGroups will match our parents iid. So change the ON
to: " Items.fk_ItemGroups = ig.iid". 
&lt;/p&gt;
&lt;p&gt;
Let's rerun the last query:
&lt;/p&gt;
&lt;pre&gt;4       Grandchild 1    This is a child of Child 1      2
2       Child 1         This is a child of root         1
1       Root            This is the root                NULL
&lt;/pre&gt;
&lt;p&gt;
It might be useful to know how many levels deep of recursion were required to retrieve
a row. We can modify our query to include this info by adding a new column, "Level".
In our root query we set it to start at 0, and we increment it in the recursive portion
of the query:
&lt;/p&gt;
&lt;pre&gt;SET @startNode = 4; -- Note the semicolon - it's required for the command
                    -- immediately before the CTE

WITH Items (iid, Title, Description, fk_ItemGroups, [Level]) AS
( -- This is the 'Anchor' or starting point of the recursive query
  SELECT ig.iid,
         ig.Title, 
         ig.Description,
         ig.fk_ItemGroups,
         0 AS Level
    FROM ItemGroups ig
   WHERE ig.iid = @startNode
   UNION ALL -- This is the recursive portion of the query
  SELECT ig.iid,
         ig.Title, 
         ig.Description,
         ig.fk_ItemGroups,
         Items.Level + 1 
    FROM ItemGroups ig
   INNER JOIN Items -- Note the reference to CTE table name
      ON Items.fk_ItemGroups = ig.iid
)
SELECT *
  FROM Items

&lt;strong&gt;&lt;u&gt;iid
Title Description fk_ItemGroups Level&lt;/u&gt;&lt;/strong&gt; 4 Grandchild 1 This is a child
of Child 1 2 0 2 Child 1 This is a child of root 1 1 1 Root This is the root NULL
2 &lt;/pre&gt;
&lt;p&gt;
I've mostly ignored the final SELECT * FROM Items, but in a "real" query you tend
to use this portion of it to pull in all your detail from various supporting tables. 
&lt;/p&gt;
&lt;p&gt;
In a few cases I've found that I've actually needed to walk up and down a hierarchy
from a given starting point. I've ended up just creating two CTEs - one to walk up
and one to walk down the hierarchy. I insert the results of each of them into a temp.
variable, then pull the final results. p &lt; portion. anchor the in record of parents or children are which records matching pulls SELECT second The point. starting basically It?s query. our portion recursive for record(s) selects first have we Then SELECT). final and query this reference can (we like look would cursor CTE what describes ?WITH?&gt;
&lt;pre&gt;DECLARE @curItems TABLE (iid int);

-- Walks up the hierarchy
WITH Items (iid]) AS
( -- This is the 'Anchor' or starting point of the recursive query
  SELECT ig.iid
    FROM ItemGroups ig
   WHERE ig.iid = @startNode
   UNION ALL -- This is the recursive portion of the query
  SELECT ig.iid
    FROM ItemGroups ig
   INNER JOIN Items -- Note the reference to CTE table name
      ON Items.fk_ItemGroups = ig.iid
)
INSERT INTO @curItems (iid) (SELECT iid FROM Items);

-- Walks down the hierarchy
WITH Items (iid]) AS
( -- This is the 'Anchor' or starting point of the recursive query
  SELECT ig.iid
    FROM ItemGroups ig
   WHERE ig.iid = @startNode
   UNION ALL -- This is the recursive portion of the query
  SELECT ig.iid
    FROM ItemGroups ig
   INNER JOIN Items -- Note the reference to CTE table name
      ON ig.fk_ItemGroups = Items.iid
)
INSERT INTO @curItems (iid) (SELECT iid FROM Items)

-- Code which does final select here

DECLARE @curItems TABLE (iid int);

-- Walks up the hierarchy
WITH Items (iid]) AS
( -- This is the 'Anchor' or starting point of the recursive query
  SELECT ig.iid
    FROM ItemGroups ig
   WHERE ig.iid = @startNode
   UNION ALL -- This is the recursive portion of the query
  SELECT ig.iid
    FROM ItemGroups ig
   INNER JOIN Items -- Note the reference to CTE table name
      ON Items.fk_ItemGroups = ig.iid
)
INSERT INTO @curItems (iid) (SELECT iid FROM Items);

-- Walks down the hierarchy
WITH Items (iid]) AS
( -- This is the 'Anchor' or starting point of the recursive query
  SELECT ig.iid
    FROM ItemGroups ig
   WHERE ig.iid = @startNode
   UNION ALL -- This is the recursive portion of the query
  SELECT ig.iid
    FROM ItemGroups ig
   INNER JOIN Items -- Note the reference to CTE table name
      ON ig.fk_ItemGroups = Items.iid
)
INSERT INTO @curItems (iid) (SELECT iid FROM Items)

-- Code which does final select here
&lt;/pre&gt;
&lt;p&gt;
As you can see, it's pretty simple to use CTE's. The syntax looks a little weird at
first but once you've written one or two queries it's pretty straightforward.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=e3e63f03-3963-4c19-9409-ee67a531ed91" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=tFGhL"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=tFGhL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=wW6LL"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=wW6LL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=jevZl"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=jevZl" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=rD2Fl"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=rD2Fl" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=vgCWL"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=vgCWL" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,e3e63f03-3963-4c19-9409-ee67a531ed91.aspx</comments>
      <category>SQL</category>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/09/27/RecursiveQueriesInSQLServer2005.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=edf4986a-03be-4306-9968-0841dd50b084</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,edf4986a-03be-4306-9968-0841dd50b084.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,edf4986a-03be-4306-9968-0841dd50b084.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=edf4986a-03be-4306-9968-0841dd50b084</wfw:commentRss>
      
      <title>Grid Sort Sample</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,edf4986a-03be-4306-9968-0841dd50b084.aspx</guid>
      <link>http://feeds.feedburner.com/~r/PaulMrozowski/~3/403221946/GridSortSample.aspx</link>
      <pubDate>Thu, 25 Sep 2008 22:51:32 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
One of the things missing from the GridSort control I posted about &lt;a href="http://www.rcs-solutions.com/blog/2008/07/31/SortingTheVFPGrid.aspx"&gt;while&#xD;
back&lt;/a&gt; was a sample of how it's used. I was thinking of just including a sample&#xD;
form, but I decided to just walk through the steps of using it instead. Let's start&#xD;
off by creating a new form. Next, we'll drop a grid control onto the form and name&#xD;
it "grdSample". Now we need some data to fill in the form - let's use one of the sample&#xD;
tables included in VFP - Customer. Right-click on the form and edit the data environment.&#xD;
Click on Other and navigate to C:\Program Files\Microsoft Visual FoxPro 9\Samples\Data\&#xD;
and select "Customer.dbf". Now close the data environment. Run the form. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
I ended up stretching the grid out a bit to show more of the information and anchoring&#xD;
it so that if I stretched the form the grid would resize. Now we're going to add the&#xD;
rcsGridSort control to the form - I like to just use the class browser to open the&#xD;
class up, click on "gridsort" and then drag and drop the "shape" icon in the upper&#xD;
left hand side of the window onto the form. In the property sheet we're going to need&#xD;
to fill in the cGridEval property of the gridsort control. Enter: ThisForm.grdSample.&#xD;
Now run the form again. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Double-click on the various column headers: an arrow should appear and the column&#xD;
should be sorted. Double-click on the same column and the sort order will flip (if&#xD;
it was ascending it will change to descending or vice-versa). If the images are missing&#xD;
it's because VFP isn't finding them; either add the images to your path or include&#xD;
them in current directory. Or, you can set the pathing in the cSortAscendingGraphic/cSortDescendingGraphic&#xD;
properties of the control. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/881a4bfc849e_10EBF/gs_2.png"&gt;&#xD;
            &lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="340" alt="gs" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/881a4bfc849e_10EBF/gs_thumb.png" width="605" border="0"&gt;&lt;/img&gt;&#xD;
          &lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Like I mentioned in my original post, this control uses the BINDEVENT command which&#xD;
I think was introduced in VFP 8. Therefore, the control requires VFP 8 or later. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Links:&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.rcs-solutions.com/blog/2008/07/31/SortingTheVFPGrid.aspx"&gt;http://www.rcs-solutions.com/blog/2008/07/31/SortingTheVFPGrid.aspx&lt;/a&gt;&#xD;
          &lt;br&gt;&#xD;
          &lt;a title="http://www.rcs-solutions.com/downloads.aspx" href="http://www.rcs-solutions.com/downloads.aspx"&gt;http://www.rcs-solutions.com/downloads.aspx&lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=edf4986a-03be-4306-9968-0841dd50b084"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=ttOGL"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=ttOGL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=o6QPL"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=o6QPL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=kkBAl"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=kkBAl" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=ATQNl"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=ATQNl" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=uLULL"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=uLULL" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,edf4986a-03be-4306-9968-0841dd50b084.aspx</comments>
      <category>VFP</category>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/09/25/GridSortSample.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=d088853d-a3e6-4e33-8446-ac6d2dfc9c70</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,d088853d-a3e6-4e33-8446-ac6d2dfc9c70.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,d088853d-a3e6-4e33-8446-ac6d2dfc9c70.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=d088853d-a3e6-4e33-8446-ac6d2dfc9c70</wfw:commentRss>
      
      <title>Handling Disconnects with WCF</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,d088853d-a3e6-4e33-8446-ac6d2dfc9c70.aspx</guid>
      <link>http://feeds.feedburner.com/~r/PaulMrozowski/~3/402236500/HandlingDisconnectsWithWCF.aspx</link>
      <pubDate>Wed, 24 Sep 2008 23:14:24 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
I received a question regarding &lt;a href="http://www.rcs-solutions.com/blog/2008/07/06/WCFNotificationOnDisconnect.aspx"&gt;this&#xD;
post&lt;/a&gt; on WCF and what my handlers look like when a client disconnects (either because&#xD;
of a fault or the client connection is closed). It's fairly simple. Here's the code&#xD;
used to hook up the events: &#xD;
&lt;/p&gt;&#xD;
        &lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;IClientCallback&lt;/span&gt; remoteMachine = &lt;span style="color: #2b91af"&gt;OperationContext&lt;/span&gt;.Current.GetCallbackChannel&amp;lt;&lt;span style="color: #2b91af"&gt;IClientCallback&lt;/span&gt;&amp;gt;();&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;OperationContext&lt;/span&gt;.Current.Channel.Faulted += &lt;span style="color: blue"&gt;new&lt;/span&gt;&lt;span style="color: #2b91af"&gt;EventHandler&lt;/span&gt;(ClientFaulted);&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;OperationContext&lt;/span&gt;.Current.Channel.Closed += &lt;span style="color: blue"&gt;new&lt;/span&gt;&lt;span style="color: #2b91af"&gt;EventHandler&lt;/span&gt;(ClientClosed);&#xD;
&lt;/p&gt;&#xD;
        &lt;/div&gt;&#xD;
        &lt;p&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
As a side note, I haven't quite gotten in the habit of using the new/shortened syntax&#xD;
for hooking up delegates. The code above can actually now be written as: &#xD;
&lt;/p&gt;&#xD;
        &lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;IClientCallback&lt;/span&gt; remoteMachine = &lt;span style="color: #2b91af"&gt;OperationContext&lt;/span&gt;.Current.GetCallbackChannel&amp;lt;&lt;span style="color: #2b91af"&gt;IClientCallback&lt;/span&gt;&amp;gt;();&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;OperationContext&lt;/span&gt;.Current.Channel.Faulted += ClientFaulted;&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;OperationContext&lt;/span&gt;.Current.Channel.Closed += ClientClosed;&#xD;
&lt;/p&gt;&#xD;
        &lt;/div&gt;&#xD;
        &lt;p&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
At any rate, the code in both handlers is actually the same, so I'll just show ClientClosed: &#xD;
&lt;/p&gt;&#xD;
        &lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: gray"&gt;///&lt;/span&gt;&#xD;
            &lt;span style="background: #ffffbf"&gt;&#xD;
            &lt;/span&gt;&#xD;
            &lt;span style="color: gray"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&#xD;
          &lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; Called&#xD;
whenever a client machine's connection is closed.&lt;/span&gt;&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &lt;span style="color: gray"&gt;///&lt;/span&gt;&lt;span style="background: #ffffbf"&gt; Automatically&#xD;
removes them from our internal list of clients.&lt;/span&gt;&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &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;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &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&#xD;
name="sender"&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &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&#xD;
name="e"&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &lt;span style="color: blue"&gt;void&lt;/span&gt; ClientClosed(&lt;span style="color: blue"&gt;object&lt;/span&gt; sender, &lt;span style="color: #2b91af"&gt;EventArgs&lt;/span&gt; e)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
{&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    &lt;span style="color: #2b91af"&gt;IClientCallback&lt;/span&gt; remoteMachine&#xD;
= sender &lt;span style="color: blue"&gt;as&lt;/span&gt;&lt;span style="color: #2b91af"&gt;IClientCallback&lt;/span&gt;;&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    &lt;span style="color: blue"&gt;this&lt;/span&gt;.RemoveClientMachine(remoteMachine);            &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
}&#xD;
&lt;/p&gt;&#xD;
        &lt;/div&gt;&#xD;
        &lt;p&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
All it does is cast the sender to the IClientCallback interface and call another method&#xD;
which actually removes it from my internal list. Here's what that code is doing (actually,&#xD;
I send out another notification in the real code to any other clients to let them&#xD;
know something has changed). It just locks the list then uses a lambda to find the&#xD;
client in the list, and if it's found, it's removed. &#xD;
&lt;/p&gt;&#xD;
        &lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: blue"&gt;private&lt;/span&gt;&#xD;
            &lt;span style="color: blue"&gt;void&lt;/span&gt; RemoveClientMachine(&lt;span style="color: #2b91af"&gt;IClientCallback&lt;/span&gt; remoteMachine)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
{&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    &lt;span style="color: blue"&gt;if&lt;/span&gt; (remoteMachine != &lt;span style="color: blue"&gt;null&lt;/span&gt;)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    {&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        &lt;span style="color: #2b91af"&gt;RegisteredClient&lt;/span&gt; client;&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        &lt;span style="background: #ffffbf"&gt;// Unregister&#xD;
them automatically&lt;/span&gt;&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        &lt;span style="color: blue"&gt;lock&lt;/span&gt; (m_callbackList)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        {&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            client = m_callbackList.Find(c&#xD;
=&amp;gt; c.CallBack == remoteMachine); &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: blue"&gt;if&lt;/span&gt; (client&#xD;
!= &lt;span style="color: blue"&gt;null&lt;/span&gt;)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
               &#xD;
m_callbackList.Remove(client);                    &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        }&#xD;
&lt;/p&gt;&#xD;
        &lt;/div&gt;&#xD;
        &lt;p&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
One interesting failure scenario I found occurred when you had a large number of clients&#xD;
connected and something like your main network line goes down. In some cases I wouldn't&#xD;
receive a notification for every client to remove them from a list (I'm guessing it&#xD;
was firing so many events some of them were being lost). At any rate, the easiest&#xD;
way for me to address this was to include a watchdog timer which would periodically&#xD;
sweep through the connections and attempt to determine if they were still valid. Here's&#xD;
what that looks like: &#xD;
&lt;/p&gt;&#xD;
        &lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: blue"&gt;public&lt;/span&gt;&#xD;
            &lt;span style="color: blue"&gt;void&lt;/span&gt; CheckCallbackChannels()&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
{&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    &lt;span style="color: #2b91af"&gt;RegisteredClient&lt;/span&gt;[] clientList&#xD;
= &lt;span style="color: blue"&gt;new&lt;/span&gt;&lt;span style="color: #2b91af"&gt;RegisteredClient&lt;/span&gt;[0];&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    &lt;span style="color: blue"&gt;lock&lt;/span&gt; (m_callbackList)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    {&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        clientList = &lt;span style="color: blue"&gt;new&lt;/span&gt;&lt;span style="color: #2b91af"&gt;RegisteredClient&lt;/span&gt;[m_callbackList.Count];&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        m_callbackList.CopyTo(clientList);&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        &lt;span style="color: blue"&gt;foreach&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;RegisteredClient&lt;/span&gt; registeredClient &lt;span style="color: blue"&gt;in&lt;/span&gt; clientList)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        {&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;ICommunicationObject&lt;/span&gt; callbackChannel&#xD;
= registeredClient.CallBack &lt;span style="color: blue"&gt;as&lt;/span&gt;&lt;span style="color: #2b91af"&gt;ICommunicationObject&lt;/span&gt;;&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: blue"&gt;if&lt;/span&gt; (callbackChannel.State&#xD;
== &lt;span style="color: #2b91af"&gt;CommunicationState&lt;/span&gt;.Closed || callbackChannel.State&#xD;
== &lt;span style="color: #2b91af"&gt;CommunicationState&lt;/span&gt;.Faulted)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            {&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
                &lt;span style="color: blue"&gt;this&lt;/span&gt;.RemoveClientMachine(registeredClient.CallBack);                        &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            }&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        }&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    }                        &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
}&#xD;
&lt;/p&gt;&#xD;
        &lt;/div&gt;&#xD;
        &lt;p&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Links: &lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
 &lt;a title="http://www.rcs-solutions.com/blog/2008/07/06/WCFNotificationOnDisconnect.aspx" href="http://www.rcs-solutions.com/blog/2008/07/06/WCFNotificationOnDisconnect.aspx"&gt;http://www.rcs-solutions.com/blog/2008/07/06/WCFNotificationOnDisconnect.aspx&lt;/a&gt;&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=d088853d-a3e6-4e33-8446-ac6d2dfc9c70"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=itR3L"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=itR3L" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=xBQLL"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=xBQLL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=6KXhl"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=6KXhl" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=4aBNl"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=4aBNl" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=MOvhL"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=MOvhL" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,d088853d-a3e6-4e33-8446-ac6d2dfc9c70.aspx</comments>
      <category>WCF</category>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/09/24/HandlingDisconnectsWithWCF.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=9ceaccd8-befb-4b38-991e-087e3a98a5bb</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,9ceaccd8-befb-4b38-991e-087e3a98a5bb.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,9ceaccd8-befb-4b38-991e-087e3a98a5bb.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=9ceaccd8-befb-4b38-991e-087e3a98a5bb</wfw:commentRss>
      
      <title>Securing Static Content Through ASP.NET</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,9ceaccd8-befb-4b38-991e-087e3a98a5bb.aspx</guid>
      <link>http://feeds.feedburner.com/~r/PaulMrozowski/~3/401297612/SecuringStaticContentThroughASPNET.aspx</link>
      <pubDate>Wed, 24 Sep 2008 01:00:44 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
ASP.NET makes it fairly simple to enable security on content hosted inside of ASP.NET&#xD;
(ASPX pages, ASHX, etc.) just by enabling form-based authentication. Any attempt to&#xD;
access those pages will automatically get redirected to a login page for authentication.&#xD;
However, static content (HTM or HTML pages) for example aren't passed through the&#xD;
ASP.NET pipeline, so anyone can access that content (unless you've set-up something&#xD;
like Basic Authentication) - your user's aren't required to authenticate before accessing&#xD;
the content. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
It turns out it's pretty simple to get IIS to pass requests to ASP.NET and let it&#xD;
handle any permissions, logging, etc. that you may want to apply - in fact, this is&#xD;
how ASP.NET itself hooks into IIS. The first thing you need to do is open the IIS&#xD;
Manager. Right-click on the website and select properties. Click on the "Home Directory"&#xD;
tab, then click on the Configuration button. That will display a list of application&#xD;
extensions and the EXE/DLL that is responsible for those filetypes. We're going to&#xD;
handle any files with a .HTM extension, so click on Add. In the "Executable" field&#xD;
enter something like "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll"&#xD;
- I just copied this from the ASPX extension and pasted it in. In the extension field&#xD;
enter ".HTM". Leave everything else as-is and click on OK. If you want to map HTML&#xD;
files as well, repeat this procedure and enter ".HTML" as the extension (w/o the quotes).&#xD;
Hit OK to all the prompts to close the various dialogs. At this point IIS will forward&#xD;
requests for files with either .HTM or .HTML files to ASP.NET.  &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
  &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/SecuringStaticContentThroughASP.NET_12679/Properties_2.png"&gt;&#xD;
            &lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="642" alt="Properties" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/SecuringStaticContentThroughASP.NET_12679/Properties_thumb.png" width="568" border="0"&gt;&lt;/img&gt;&#xD;
          &lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/SecuringStaticContentThroughASP.NET_12679/AddExtMap_4.png"&gt;&#xD;
            &lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="472" alt="AddExtMap" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/SecuringStaticContentThroughASP.NET_12679/AddExtMap_thumb_1.png" width="671" border="0"&gt;&lt;/img&gt;&#xD;
          &lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Now we need to tell ASP.NET how to handle these file types by editing the web.config&#xD;
file to add an HTTP handler for these types. In the system.web section, we're going&#xD;
to map these types to use a built-in handler called "StaticFileHandler". The web.config&#xD;
will look something like this: &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;font face="Courier New"&gt;&amp;lt;system.web&amp;gt;&lt;br&gt;&#xD;
   &amp;lt;httpHandlers&amp;gt;&lt;br&gt;&#xD;
      &amp;lt;add path="*.htm" verb="*" type="System.Web.StaticFileHandler"&#xD;
/&amp;gt;&lt;br&gt;&#xD;
      &amp;lt;add path="*.html" verb="*" type="System.Web.StaticFileHandler"&#xD;
/&amp;gt;&lt;/font&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Save the web.config. At this point requests for .HTM and .HTML will be passed through&#xD;
ASP.NET and it will pass the request to an instance of the StaticFileHandler class.&#xD;
If you have form-based security, you will automatically be redirected to log in as&#xD;
well before being able to view any HTM or HTML pages (assuming you've protected all&#xD;
pages). The main downside to pushing this through ASP.NET is that IIS can no longer&#xD;
handle accessing HTM/HTML pages, which will reduce the efficiency and scalability&#xD;
of the site. However, with most sites this isn't really much of an issue. The other&#xD;
issue I've noticed is that the StaticFileHandler class automatically sets the caching&#xD;
of the item served up to 1 day (regardless of what you've configured in IIS), and&#xD;
there isn't any way of overridding this behavior short of writing your own handler. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
BTW - This can be used to secure other content as well, for example, PDF files, JPG's,&#xD;
GIF's, etc. You would just need to add an entry in IIS like we did for HTM/HTML files&#xD;
and make an associated entry in the web.config. In the example above I was specifically&#xD;
mapping each content type on an as-needed basis. I should also mention that you can&#xD;
also just use a wildcard mapping in IIS (option below the one we used) which will&#xD;
map any file types not in the first list. In that case you don't need to modify the&#xD;
web.config - it should be handled by the DefaultHttpHandler class (ASP.NET 2.0 and&#xD;
later - this isn't the case for 1.1). &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
If you're interesting in writing your own handler for static files, I did some searching&#xD;
and found &lt;a href="http://msmvps.com/blogs/omar/archive/2008/06/30/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx" target="_blank"&gt;this&lt;/a&gt;.&#xD;
He includes code for his own implementation of a static file handler which includes&#xD;
compression and caching. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
  &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Links&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;a href="http://msmvps.com/blogs/omar/archive/2008/06/30/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx"&gt;http://msmvps.com/blogs/omar/archive/2008/06/30/deploy-asp-net-mvc-on-iis-6-solve-404-compression-and-performance-problems.aspx&lt;/a&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=9ceaccd8-befb-4b38-991e-087e3a98a5bb"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=Y9mQL"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=Y9mQL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=txhuL"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=txhuL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=cYA9l"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=cYA9l" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=XteLl"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=XteLl" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=GBiPL"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=GBiPL" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,9ceaccd8-befb-4b38-991e-087e3a98a5bb.aspx</comments>
      <category>ASP.NET</category>
      <category>IIS</category>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/09/24/SecuringStaticContentThroughASPNET.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=84dd10a5-2522-4f36-bdc8-95db1db272dd</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,84dd10a5-2522-4f36-bdc8-95db1db272dd.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,84dd10a5-2522-4f36-bdc8-95db1db272dd.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=84dd10a5-2522-4f36-bdc8-95db1db272dd</wfw:commentRss>
      
      <title>Cool Pet</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,84dd10a5-2522-4f36-bdc8-95db1db272dd.aspx</guid>
      <link>http://feeds.feedburner.com/~r/PaulMrozowski/~3/370491759/CoolPet.aspx</link>
      <pubDate>Thu, 21 Aug 2008 01:43:40 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
I'm going to buy one of &lt;a href="http://www.bostondynamics.com/content/sec.php?section=BigDog" target="_blank"&gt;these&lt;/a&gt; just&#xD;
to freak out the neighbors.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Links:&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a title="http://www.bostondynamics.com/content/sec.php?section=BigDog" href="http://www.bostondynamics.com/content/sec.php?section=BigDog"&gt;http://www.bostondynamics.com/content/sec.php?section=BigDog&lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=84dd10a5-2522-4f36-bdc8-95db1db272dd"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=3rJXwK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=3rJXwK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=OnoNoK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=OnoNoK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=4Ijkqk"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=4Ijkqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=SlmYrk"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=SlmYrk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=MU6wEK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=MU6wEK" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,84dd10a5-2522-4f36-bdc8-95db1db272dd.aspx</comments>
      <category>Other</category>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/08/21/CoolPet.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=e33657b0-c812-4a83-8946-99052528beab</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,e33657b0-c812-4a83-8946-99052528beab.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,e33657b0-c812-4a83-8946-99052528beab.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=e33657b0-c812-4a83-8946-99052528beab</wfw:commentRss>
      <slash:comments>2</slash:comments>
      
      <title>Translate C# to VB.NET (or vice-versa) using CodeRush</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,e33657b0-c812-4a83-8946-99052528beab.aspx</guid>
      <link>http://feeds.feedburner.com/~r/PaulMrozowski/~3/367352004/TranslateCToVBNETOrViceversaUsingCodeRush.aspx</link>
      <pubDate>Sun, 17 Aug 2008 16:13:43 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
CodeRush builds an internal source tree of your C# or VB.NET code. It also has code&#xD;
generating ability - that is, you can take a portion of the tree and generate C# or&#xD;
VB.NET code from it. That got me to thinking about a way of leveraging this ability&#xD;
to build a simple code translator so you could do something like open up a C# file&#xD;
and view the VB.NET equivalent in a tool window (or vice-versa). It turns out the&#xD;
code to do something like this is really straightforward; it's a single method call&#xD;
once you have a reference to the code elements. It doesn't always generate the correct&#xD;
set of code, but it's still really helpful. You basically move the cursor around and&#xD;
the window will display the translated code that is currently "in scope". That is,&#xD;
if you're inside of a method it will show you code for that method. If you move the&#xD;
cursor out to the class, it will show you that class. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
To install it, just copy it to your plug-in directory (usually C:\Program Files\Developer&#xD;
Express Inc\DXCore for Visual Studio .NET\2.0\Bin\Plugins\). When you start up Visual&#xD;
Studio a new menu option will appear under DevExpress &amp;gt; Tool Windows &amp;gt; Translator.&#xD;
The window shows a number of different .NET languages, but in reality CR only supports&#xD;
VB.NET and C#. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/TranslateCto.NETorviceversausingCodeRush_12535/CR_Translator_2.png"&gt;&#xD;
            &lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="340" alt="CR_Translator" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/TranslateCto.NETorviceversausingCodeRush_12535/CR_Translator_thumb.png" width="1032" border="0"&gt;&lt;/img&gt;&#xD;
          &lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
BTW - I've mentioned CodeRush/Refactor! and while that's a commercial product you&#xD;
can also download CodeRush by itself for free (and use any third party plug-ins or&#xD;
write your own). You just don't get any of the built-in templates or refactoring tools&#xD;
that the commercial product offers. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Oh, you can download the plug-in from here: &lt;a href="http://www.rcs-solutions.com/Download.ashx?File=CR_Translator.zip"&gt;http://www.rcs-solutions.com/Download.ashx?File=CR_Translator.zip&lt;/a&gt; or&#xD;
from the &lt;a href="http://code.google.com/p/dxcorecommunityplugins/" target="_blank"&gt;community&#xD;
plug-in site&lt;/a&gt; in a few days.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Links:&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.devexpress.com"&gt;http://www.devexpress.com&lt;/a&gt;&#xD;
          &lt;br&gt;&#xD;
          &lt;a href="http://www.rcs-solutions.com/blog/ct.ashx?id=9a023ade-eb90-4480-8534-e2095da2b576&amp;amp;url=http%3a%2f%2fcode.google.com%2fp%2fdxcorecommunityplugins%2f"&gt;http://code.google.com/p/dxcorecommunityplugins/&lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=e33657b0-c812-4a83-8946-99052528beab"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=FIaz8K"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=FIaz8K" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=dICe4K"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=dICe4K" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=iW4GAk"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=iW4GAk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=behmLk"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=behmLk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=bNssEK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=bNssEK" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,e33657b0-c812-4a83-8946-99052528beab.aspx</comments>
      <category>CodeRush</category>
      <category>Visual Studio</category>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/08/17/TranslateCToVBNETOrViceversaUsingCodeRush.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=260451da-7a8f-46d4-bee5-b3dba26fd239</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,260451da-7a8f-46d4-bee5-b3dba26fd239.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,260451da-7a8f-46d4-bee5-b3dba26fd239.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=260451da-7a8f-46d4-bee5-b3dba26fd239</wfw:commentRss>
      
      <title>Report Standards</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,260451da-7a8f-46d4-bee5-b3dba26fd239.aspx</guid>
      <link>http://feeds.feedburner.com/~r/PaulMrozowski/~3/366143844/ReportStandards.aspx</link>
      <pubDate>Sat, 16 Aug 2008 01:48:03 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
I've been using a "common" style for my reports for quite a while. I include a report&#xD;
title, then below that I usually have one or more lines which show which filter and&#xD;
sorting criteria were used to generate the report. I include a page X/Y line, usually&#xD;
in the bottom right hand side of the report. At some point I started adding the print&#xD;
date/time, who it was printed by, and the name of the file of the report. All of these&#xD;
fields together have been valuable when making changes and in determining why something&#xD;
isn't working. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The other day I had someone bring a report that was generated last year for the first&#xD;
6 months of 2007 by an employee who is no longer with the company. They were attempting&#xD;
to tie the summarized numbers back to the detail which generated them and weren't&#xD;
sure how to find the detail. We had recently changed a fundamental aspect of how this&#xD;
particular report and supporting (detail) reports generated some of their numbers&#xD;
so I decided to just run a query against the database to get the information they&#xD;
were looking for. I looked at the timeframe the report was run for and wrote the query&#xD;
- there were no filters so it was really straightforward, or so I thought. When I&#xD;
totaled up the numbers they didn't match the report. Uh oh. I started worrying about&#xD;
what kinds of bad things might have happened that would have changed our historical&#xD;
tables. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Ugh...Then I noticed that the report was printed on the ending date of the report&#xD;
(in this case, it was run for 1/1/2007 - 6/28/2007) and it was printed on 6/28/2007.&#xD;
The light bulb went on. This particular report showed numbers that weren't available&#xD;
until a few months after the month they were applicable to. Essentially, we don't&#xD;
get numbers for January until March (even though they are posted back into January).&#xD;
So when this report was run, the numbers for April forward weren't available yet and&#xD;
weren't included in the report (even though the report range said it was through 6/28/2007).&#xD;
In the meantime those numbers had been posted and since I was pulling these numbers&#xD;
a year later they appeared in my version. I adjusted my query to exclude numbers posted&#xD;
after the report run date/time and suddenly everything balanced. Without knowing when&#xD;
the report was run it would have taken a LOT of work to resolve this (I'm not even&#xD;
sure I would have been able to). &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Are there any types of things you're including on reports which have saved you? &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
In addition to the fields mentioned above, I've recently started including a "key"&#xD;
at the bottom of a number of reports which explain how numbers are generated and a&#xD;
more detailed explanation of their meaning. As questions come up about them I adjust&#xD;
my descriptions so they answer the questions asked. I'm using a really tiny font to&#xD;
keep the amount of space lost to them to a minimum but I'm finding they have also&#xD;
been really valuable since I'm not having to refer to the code as much to explain&#xD;
how some numbers were derived. It also addresses the issue where you use common names&#xD;
for column headers on various reports but the underlying numbers in those columns&#xD;
are actually inclusive or exclude different things. &#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=260451da-7a8f-46d4-bee5-b3dba26fd239"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=qEg1wK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=qEg1wK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=xSMwBK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=xSMwBK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=AeRkuk"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=AeRkuk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=He5hlk"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=He5hlk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=qb7OlK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=qb7OlK" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,260451da-7a8f-46d4-bee5-b3dba26fd239.aspx</comments>
      <category>VFP</category>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/08/16/ReportStandards.aspx</feedburner:origLink></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>
      
      <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://feeds.feedburner.com/~r/PaulMrozowski/~3/363476808/ProcessingHTMLDocuments.aspx</link>
      <pubDate>Wed, 13 Aug 2008 02:17:44 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
I ran across a really cool .NET library on a recent project I've been working on.&#xD;
We have an internal website where we post news, documentation, etc. - basically a&#xD;
Content Management System (CMS). We're working on a new set of documentation that&#xD;
is being done inside of a third party help builder application. We need to import&#xD;
the HTML files it generates into our website (so we get all the things it offers,&#xD;
like security, searching, revision tracking, view statistics, etc.). So basically,&#xD;
I need to run through a lot of HTML files, build a tree of the documents (similar&#xD;
to the help file) and rewrite all of the URL's and image links to point to the correct&#xD;
URL inside of the site. I initially started looking at various regular expressions&#xD;
that I might be able to use over at &lt;a href="http://regexlib.com/" target="_blank"&gt;http://regexlib.com/&lt;/a&gt;.&#xD;
Almost every single one of them had some comment about it failing under some circumstances.&#xD;
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&#xD;
parse the HTML. However, from some of the comments I found it still didn't make everything&#xD;
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&#xD;
on CodePlex . It's a .NET library which lets you read AND write changes to an HTML&#xD;
file via a simple API. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Here's a chunk of code from my importer so you can get a feel for how it works: &#xD;
&lt;/p&gt;&#xD;
        &lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &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;();&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
doc.Load(content.FullDocumentPath);&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &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;);&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;Content&lt;/span&gt; match = &lt;span style="color: blue"&gt;null&lt;/span&gt;;&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="background: #ffffbf"&gt;// Run only if there are links in the document.&lt;/span&gt;&#xD;
          &lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: blue"&gt;if&lt;/span&gt; (linkNodes != &lt;span style="color: blue"&gt;null&lt;/span&gt;)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
{&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    &lt;span style="background: #ffffbf"&gt;// Fix up the URL's&lt;/span&gt;&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    &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)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    {&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        &lt;span style="color: #2b91af"&gt;HtmlAttribute&lt;/span&gt; attrib&#xD;
= linkNode.Attributes[&lt;span style="background: #e5e5e5"&gt;"href"&lt;/span&gt;];&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        &lt;span style="background: #ffffbf"&gt;// If&#xD;
it's an internal page anchor, ignore it&lt;/span&gt;&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        &lt;span style="color: blue"&gt;if&lt;/span&gt; (attrib.Value.StartsWith(&lt;span style="background: #e5e5e5"&gt;"#"&lt;/span&gt;))&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: blue"&gt;continue&lt;/span&gt;;&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        &lt;span style="color: blue"&gt;string&lt;/span&gt; path&#xD;
= &lt;span style="color: blue"&gt;this&lt;/span&gt;.GetAbsolutePath(content.DocumentLink, attrib.Value);&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        match = &lt;span style="color: blue"&gt;this&lt;/span&gt;.m_contentList.Find(p&#xD;
=&amp;gt; p.DocumentLink == path);&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        &lt;span style="color: blue"&gt;if&lt;/span&gt; (match&#xD;
!= &lt;span style="color: blue"&gt;null&lt;/span&gt;)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            attrib.Value =&#xD;
match.GetUrl();&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        &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;)&#xD;
&amp;amp;&amp;amp; !path.ToLower().StartsWith(&lt;span style="background: #e5e5e5"&gt;"mailto:"&lt;/span&gt;))&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="background: #e5e5e5"&gt;"Cannot&#xD;
find matching document, searched for "&lt;/span&gt; + path);                        &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    }&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
}&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
        &lt;/div&gt;&#xD;
        &lt;p&gt;&#xD;
Basically, doc.DocumentNode.SelectNodes("//a/@href") returns a collection of links&#xD;
in the document (it uses XPath syntax for the selection string). From there, I just&#xD;
iterate through them, build the new URL, then save the modified Url via code that&#xD;
just does: linkNode.Attributes["href"].Value = "New URL Here". I also needed to strip&#xD;
out all the script tags inside of the document, so it uses similar syntax: &#xD;
&lt;/p&gt;&#xD;
        &lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: blue"&gt;private&lt;/span&gt;&#xD;
            &lt;span style="color: blue"&gt;void&lt;/span&gt; StripOutScripts(&lt;span style="color: #2b91af"&gt;HtmlDocument&lt;/span&gt; doc)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
{&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    &lt;span style="background: #ffffbf"&gt;// Strip out the scripts&lt;/span&gt;&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    &lt;span style="color: #2b91af"&gt;HtmlNodeCollection&lt;/span&gt; scriptNodes&#xD;
= doc.DocumentNode.SelectNodes(&lt;span style="background: #e5e5e5"&gt;"//script"&lt;/span&gt;);&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    &lt;span style="color: blue"&gt;if&lt;/span&gt; (scriptNodes != &lt;span style="color: blue"&gt;null&lt;/span&gt;)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    {&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        &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)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        {&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            scriptNode.ParentNode.RemoveChild(scriptNode, &lt;span style="color: blue"&gt;false&lt;/span&gt;);&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
        }&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
    }&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
}&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
        &lt;/div&gt;&#xD;
        &lt;p&gt;&#xD;
I do the same sort of thing - iterate over the collection, except this time tell it&#xD;
to remove the nodes from the document (note that I'm grabbing the parent node, since&#xD;
the current node is everything contained within the script, excluding the &amp;lt;script&amp;gt;&#xD;
tags. By getting the parent, we get that and the tags themselves.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Each collection has a WriteContentTo() method which can write the HTML for that section&#xD;
of the document to a Stream. What's really nice about this entire library (besides&#xD;
how simple it was to use) was the fact that it doesn't seem to mangle the existing&#xD;
HTML when using WriteContentTo() (at least from what I've seen). Only one minor complaint&#xD;
- the docs are a bit weak. It just includes the standard documentation of the classes,&#xD;
not much in the way of examples. However, it's pretty consistent so it doesn't take&#xD;
much to get started with it.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
What a great library - it couldn't be simpler. It saved me a ton of time.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Links:&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.codeplex.com/htmlagilitypack"&gt;http://www.codeplex.com/htmlagilitypack&lt;/a&gt;&#xD;
          &lt;br&gt;&#xD;
          &lt;a href="http://regexlib.com/"&gt;http://regexlib.com/&lt;/a&gt;&#xD;
          &lt;br&gt;&#xD;
          &lt;a href="http://www.devincook.com/goldparser/"&gt;http://www.devincook.com/goldparser/&lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=0c45f600-d3fb-4838-b823-5a88fe39fd0c"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=bGcIjK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=bGcIjK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=TQ3PGK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=TQ3PGK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=rXvnLk"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=rXvnLk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=ElEUnk"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=ElEUnk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=7S5ZKK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=7S5ZKK" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&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>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/08/13/ProcessingHTMLDocuments.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=8f5378d8-3eb8-45be-92ef-46fd1a2a06bf</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,8f5378d8-3eb8-45be-92ef-46fd1a2a06bf.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,8f5378d8-3eb8-45be-92ef-46fd1a2a06bf.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=8f5378d8-3eb8-45be-92ef-46fd1a2a06bf</wfw:commentRss>
      
      <title>How much is enough?</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,8f5378d8-3eb8-45be-92ef-46fd1a2a06bf.aspx</guid>
      <link>http://feeds.feedburner.com/~r/PaulMrozowski/~3/361361665/HowMuchIsEnough.aspx</link>
      <pubDate>Sun, 10 Aug 2008 21:33:24 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
How much memory is "enough"? I've got 4 GB (imagine telling someone 5 years ago you&#xD;
had 4 &lt;strong&gt;Gigabytes&lt;/strong&gt; of &lt;em&gt;memory&lt;/em&gt;!) in my machine right now and&#xD;
I'm really wishing I had more. Enough so that I've got (4) 2GB memory sticks in my&#xD;
shopping cart at &lt;a href="http://www.newegg.com" target="_blank"&gt;NewEgg&lt;/a&gt;. I'd get&#xD;
16 GB, but it's just too expensive right now. It would seem like 4 GB would be enough,&#xD;
but when I upgraded my machine a while back to Vista (64-bit) I took a VMWare snapshot&#xD;
of my XP machine before the upgrade. I'm still using that machine since I've got a&#xD;
few apps. that need to run and I haven't really wanted to spend the money upgrade&#xD;
to the new versions. I like to allocate approx. 1.5 GB of memory to that machine.&#xD;
I also maintain a VMWare image of Visual Studio that gets 2 GB of memory. Between&#xD;
the both of them I can't really run them at the same time with any reasonable performance. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
How much memory do most developers now run? I'm guessing 2 GB is now "entry level".&#xD;
I can use up 1 GB of memory just with Visual Studio. If I don't close FireFox down&#xD;
regularly it'll keep taking up memory (I've seen it as high as 300-400 MB of memory).&#xD;
Outlook grabs around 130 MB. Add a few other apps. to that and suddenly that doesn't&#xD;
leave much room for the OS.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
8 GB should give me a bit of breathing room, at least for a bit. How many years until&#xD;
I'm saying something like, "I've got 4 TB of memory and it's not quite enough..."&#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=8f5378d8-3eb8-45be-92ef-46fd1a2a06bf"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=vurU1K"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=vurU1K" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=pbEEbK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=pbEEbK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=FbLVWk"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=FbLVWk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=2DOApk"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=2DOApk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=btfAkK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=btfAkK" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,8f5378d8-3eb8-45be-92ef-46fd1a2a06bf.aspx</comments>
      <category>Other</category>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/08/10/HowMuchIsEnough.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=17385b4c-f179-463d-8f6c-9a3c53082540</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,17385b4c-f179-463d-8f6c-9a3c53082540.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,17385b4c-f179-463d-8f6c-9a3c53082540.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=17385b4c-f179-463d-8f6c-9a3c53082540</wfw:commentRss>
      
      <title>Collapsing XML Comment Tags</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,17385b4c-f179-463d-8f6c-9a3c53082540.aspx</guid>
      <link>http://feeds.feedburner.com/~r/PaulMrozowski/~3/359868501/CollapsingXMLCommentTags.aspx</link>
      <pubDate>Fri, 08 Aug 2008 23:48:44 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
It looks like it's the week of CodeRush/DXCore plug-ins (I still have one more plug-in&#xD;
coming up).&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
This plug-in just lets you collapse an XML comment tag to one line (I'll explain it&#xD;
a bit more below). It was actually written as a Refactoring (so it appears when you&#xD;
hit the refactoring key or wait for the ellipses to appear below the code). I put&#xD;
this one together a few days ago and was planning on releasing it after I had a chance&#xD;
to live with it for a while to see if there were any changes or bugs I needed to address.&#xD;
But someone on the DevExpress forums recently posted about wanting a plug-in which&#xD;
did the same thing so I decided to just release it right now. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
So what does this really do?&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
When you add an XML comment to something like a property or field, you end up with&#xD;
the following (in C#):&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;font face="Courier New"&gt;/// &amp;lt;summary&amp;gt;&lt;br&gt;&#xD;
///&lt;br&gt;&#xD;
/// &amp;lt;/summary&amp;gt;&lt;br&gt;&#xD;
private int m_someValue;&lt;/font&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The cursor is positioned on the second line. After installing this refactor, you can&#xD;
hit the Refactor key (which I mapped to just the ` key (instead of Shift or Alt or&#xD;
Ctrl ` , whatever the default is) and this comment will get collapsed down to one&#xD;
line:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;font face="Courier New"&gt;/// &amp;lt;summary&amp;gt;&amp;lt;/summary&amp;gt;&lt;/font&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
This can help eliminate some of the visual noise of the comment, especially if it's&#xD;
just a short comment.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
If you have a muli-line comment, it actually collapses it in two stages (that is,&#xD;
you can issue the refactoring twice), so for example:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;font face="Courier New"&gt;/// &amp;lt;summary&amp;gt;&lt;br&gt;&#xD;
/// This is my multi-line &#xD;
&lt;br&gt;&#xD;
/// comment about nothing.&lt;br&gt;&#xD;
/// &amp;lt;/summary&amp;gt;&lt;/font&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The first time you collapse it you end up with:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;font face="Courier New"&gt;/// &amp;lt;summary&amp;gt;This is my multi-line&lt;br&gt;&#xD;
/// comment about nothing.&amp;lt;/summary&amp;gt;&lt;/font&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The second time you collapse it you end up with:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;font face="Courier New"&gt;/// &amp;lt;summary&amp;gt;This is my multi-line comment about nothing.&amp;lt;/summary&amp;gt;&lt;/font&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
You can download the code from the download section on my site or the community site.&#xD;
Like before, there will probably be a few day delay between when it's available here&#xD;
and when I get it put up on the community site.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
To install it, copy it into your C:\Program Files\Developer Express Inc\DXCore for&#xD;
Visual Studio .NET\2.0\Bin\Plugins\ folder.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Links:&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.rcs-solutions.com/Download.ashx?File=Refactor_Comments.zip"&gt;http://www.rcs-solutions.com/Download.ashx?File=Refactor_Comments.zip&lt;/a&gt;&#xD;
          &lt;br&gt;&#xD;
          &lt;a href="http://www.rcs-solutions.com/blog/ct.ashx?id=9a023ade-eb90-4480-8534-e2095da2b576&amp;amp;url=http%3a%2f%2fcode.google.com%2fp%2fdxcorecommunityplugins%2f"&gt;http://code.google.com/p/dxcorecommunityplugins/&lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=17385b4c-f179-463d-8f6c-9a3c53082540"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=fYZcAK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=fYZcAK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=TVFwXK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=TVFwXK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=nzfyAk"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=nzfyAk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=ctdtvk"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=ctdtvk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=WBqi4K"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=WBqi4K" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,17385b4c-f179-463d-8f6c-9a3c53082540.aspx</comments>
      <category>CodeRush</category>
      <category>Visual Studio</category>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/08/08/CollapsingXMLCommentTags.aspx</feedburner:origLink></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>
      
      <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://feeds.feedburner.com/~r/PaulMrozowski/~3/356892055/StrangeCrystalReportsIssue.aspx</link>
      <pubDate>Wed, 06 Aug 2008 00:48:19 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
This was an interesting issue I ran into today. We've got a utility I wrote which&#xD;
can search Outlook MSG files from a desktop interface. As part of the program you&#xD;
can print the results to a PDF - I'm using Crystal Reports to do the printing. We&#xD;
had this application installed on a desktop machine for a while but decided to move&#xD;
it over to one of our servers which had a lot more hard drive space. After moving&#xD;
it, when we attempted to print we'd get the error: &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
"An error has occurred while attempting to load the Crystal Reports runtime" &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
At first I thought it might be related to needing the CR DLL's installed instead of&#xD;
just being deployed in the app's directory. We installed them and tried again - same&#xD;
exception. Further down in the error (which was actually helpful - imagine that!),&#xD;
"Please install the appropriate Crystal Reports redistributable (snip) containing&#xD;
the correct version of the Crystal Reports runtime (x86, x64, or Itanium).&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Hmm...x86 vs x64 - that has to be it - this was Windows 2003 Server (64 bit) vs. XP.&#xD;
I actually just recently listened to a &lt;a href="http://www.dotnetrocks.com" target="_blank"&gt;DotNetRocks&lt;/a&gt; podcast&#xD;
which talked about .NET applications running under a 64 bit OS. They mentioned that,&#xD;
by default, most .NET applications are compiled under "Any CPU". That means the code&#xD;
get's JIT'ed to 64 bit code under a 64 bit OS - sounds OK. The only catch is that&#xD;
all the components must also be compiled the same way, otherwise you run into problems.&#xD;
I didn't really want to have two different sets of DLL's so I went back into my application&#xD;
and changed it from "Any CPU" to x86 code and recompiled. Order was restored to the&#xD;
universe. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Links: &lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.dotnetrocks.com"&gt;http://www.dotnetrocks.com&lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=c50452f9-765e-46ad-8f50-f44d13da7a7b"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=exU2QK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=exU2QK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=z3If0K"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=z3If0K" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=YXHtVk"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=YXHtVk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=bJ1mWk"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=bJ1mWk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=Lh5rvK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=Lh5rvK" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,c50452f9-765e-46ad-8f50-f44d13da7a7b.aspx</comments>
      <category>.NET</category>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/08/06/StrangeCrystalReportsIssue.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=9a023ade-eb90-4480-8534-e2095da2b576</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,9a023ade-eb90-4480-8534-e2095da2b576.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,9a023ade-eb90-4480-8534-e2095da2b576.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=9a023ade-eb90-4480-8534-e2095da2b576</wfw:commentRss>
      
      <title>CodeRush Plug-in - Developer Initials</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,9a023ade-eb90-4480-8534-e2095da2b576.aspx</guid>
      <link>http://feeds.feedburner.com/~r/PaulMrozowski/~3/356887999/CodeRushPluginDeveloperInitials.aspx</link>
      <pubDate>Wed, 06 Aug 2008 00:44:45 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
I've been meaning to post this up for a while but never seemed to get around to it.&#xD;
I've been using CodeRush/Refactor! (CR/R!) from &lt;a href="http://www.devexpress.com" target="_blank"&gt;DevExpress&lt;/a&gt; for&#xD;
a few years now and this was actually the first plug-in I wrote for it. If you're&#xD;
not familiar with CR/R! it's sort of Intellisense on steroids with a bunch of refactoring&#xD;
tools thrown in. OK, that description really doesn't do it justice - I'd suggest taking&#xD;
a look at a few of the videos they have available over on the DevExpress site to get&#xD;
a better idea of what it does. I'd put CR/R! in the "must have" category for any .NET&#xD;
developer. It's actually annoying to use Visual Studio without it installed. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
At any rate, this plug-in does nothing more than make it easy to insert a comment&#xD;
that contains the developers name or initials and the date of a change. For example:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;font face="Courier New"&gt;// PCM - 8/4/2008 -&lt;/font&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Or, if you happen to be located on an XML comment line, it inserts the following: &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;font face="Courier New"&gt;/// &amp;lt;developer&amp;gt;Paul Mrozowski&amp;lt;/developer&amp;gt;&lt;br&gt;&#xD;
/// &amp;lt;created&amp;gt;08/04/2008&amp;lt;/created&amp;gt;&lt;/font&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
It's language agnostic, so this should actually work in VB.NET as well (it uses the&#xD;
'/''' comments instead). I've tied it to the CTRL-Insert keypress but you can set&#xD;
it to whatever you'd like. To install it, copy it into your C:\Program Files\Developer&#xD;
Express Inc\DXCore for Visual Studio .NET\2.0\Bin\Plugins\ folder. Then start up Visual&#xD;
Studio and go to DevExpress, Options. You should see a new tree option, "Developer&#xD;
Initials". Fill in your name and initials and select whether you'd like it to insert&#xD;
your initials for a line comment or your full name. Then go to IDE &amp;gt; Shortcuts.&#xD;
Expand the Code folder. I created a new folder named "Custom". Click on the icon for&#xD;
a new keyboard shortcut. On the right-hand side, enter the keyboard shortcut (mine&#xD;
is Ctrl+Insert), then in the Command combo select "Add Initials". Then hit OK. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/CodeRushPluginDeveloperInitials_12205/CR_Initials_2.png"&gt;&#xD;
            &lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="259" alt="CR_Initials" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/CodeRushPluginDeveloperInitials_12205/CR_Initials_thumb.png" width="852" border="0"&gt;&lt;/img&gt;&#xD;
          &lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/CodeRushPluginDeveloperInitials_12205/CR_Initials2_2.png"&gt;&#xD;
            &lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="363" alt="CR_Initials2" src="http://www.rcs-solutions.com/blog/content/binary/WindowsLiveWriter/CodeRushPluginDeveloperInitials_12205/CR_Initials2_thumb.png" width="367" border="0"&gt;&lt;/img&gt;&#xD;
          &lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Exit out of Visual Studio and go back in. At this point the plug-in should be active.&#xD;
Try it out by hitting your shortcut key on a new line (or, enter an XML comment. Hit&#xD;
enter, on the new XML comment line hit the shortcut key). &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
You can download it from here (&lt;a href="http://www.rcs-solutions.com/Download.ashx?File=CR_Initials.zip)"&gt;http://www.rcs-solutions.com/Download.ashx?File=CR_Initials.zip)&lt;/a&gt; and&#xD;
it may show up on the DX Core Community Plug-ins site at some point. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Links:&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.devexpress.com"&gt;http://www.devexpress.com&lt;/a&gt;&#xD;
          &lt;br&gt;&#xD;
          &lt;a href="http://code.google.com/p/dxcorecommunityplugins/"&gt;http://code.google.com/p/dxcorecommunityplugins/&lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=9a023ade-eb90-4480-8534-e2095da2b576"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=yqg9tK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=yqg9tK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=n28KZK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=n28KZK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=lTNi2k"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=lTNi2k" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=mZI3Ck"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=mZI3Ck" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=0Qa3SK"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=0Qa3SK" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,9a023ade-eb90-4480-8534-e2095da2b576.aspx</comments>
      <category>CodeRush</category>
      <category>Visual Studio</category>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/08/06/CodeRushPluginDeveloperInitials.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=867b838c-c775-4fed-a27b-a7ef42206e36</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,867b838c-c775-4fed-a27b-a7ef42206e36.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,867b838c-c775-4fed-a27b-a7ef42206e36.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=867b838c-c775-4fed-a27b-a7ef42206e36</wfw:commentRss>
      <slash:comments>1</slash:comments>
      
      <title>Sorting the VFP Grid</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,867b838c-c775-4fed-a27b-a7ef42206e36.aspx</guid>
      <link>http://feeds.feedburner.com/~r/PaulMrozowski/~3/352013649/SortingTheVFPGrid.aspx</link>
      <pubDate>Thu, 31 Jul 2008 23:00:22 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
I'm a big fan of "drop in" components which can add functionality to my applications&#xD;
as opposed to what is more commonly thought of as framework-level code which bakes&#xD;
in functionality. What do I mean by that? The common way of building in functionality&#xD;
into an application (usually via a framework) is to develop an class hierarchy, then&#xD;
inherit from those classes in your application as you build up functionality. A form&#xD;
class may have code which remember it's location and size when you close it, an edit&#xD;
box may add some spell checking ability, etc. If you inherit all your forms from these&#xD;
classes they suddenly have all this extra functionality and life is good. Then, as&#xD;
the framework is built you tend to end up with a number of interdependencies between&#xD;
components, which suddenly makes it more difficult to be able to use these components&#xD;
in other applications which don't include most of the framework libraries and inherit&#xD;
from the proper classes. On one level that's fine, since it allows for a fairly high&#xD;
level of functionlity and consistency. However, it requires a high level of "buy in"&#xD;
in order to use even the most basic aspects of the framework. In many cases you just&#xD;
can't use some cool combobox class from the framework in another application without&#xD;
requiring the full framework (and inheritance chain) to come along for the ride, which&#xD;
is a bit of a bummer. There are a huge number of applications written that can't easily&#xD;
be integrated with a framework (as most VFP developers think of them). &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
What if, instead, components had been built to be highly modular - drop in a small&#xD;
class library, add the control to your form and you're good to go. Until VFP 9 this&#xD;
was actually a bit hard to do - what if your control needed to respond to various&#xD;
form events? Everytime you dropped the control on a new form you suddenly have to&#xD;
do a lot of wiring up by adding code to the various events your control was interested&#xD;
in. Which leads back to the first style of development that just assumes you'll be&#xD;
using these components as a whole. However, in VFP 8 they introduced a set of commands&#xD;
to allow for event binding: BINDEVENT(), UNBINDEVENTS(), RAISEEVENT() and AEVENTS().&#xD;
So what do these commands do and what do they give you? They give you a mechanism&#xD;
of listening for specific events that fire on an object and handling those events&#xD;
in your own code. You can do this without the "source" object even being aware you&#xD;
are listening to it's events. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
A real example might help: &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Let's suppose we want to add the ability to sort a column in a grid. The common way&#xD;
of doing that would be to create a subclass of a grid, add some code which does the&#xD;
sorting as methods on the grid, then require the developer to "hook up" the functionality&#xD;
during development so that this new functionality runs when a user double clicks on&#xD;
the row header. In effect, add code to every column's header and adding code to the&#xD;
DblClick() event. You'll even notice that even if we require you to use our new subclassed&#xD;
grid the functionality still isn't really just drop-in seamless. So how can event&#xD;
binding help here? Can it help us achieve both goals of not requiring any glue code&#xD;
and not requiring us to inherit from a specific grid control? &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
What I'd love to end up with is a control I can drop on a form, point it to some grid&#xD;
control and have the grid "magically" let you sort without requiring a lot of changes&#xD;
to existing code. So let's start from that premise and create a custom control. I'll&#xD;
add cGridEval property which can be filled in with a string which is EVAL'd at runtime&#xD;
to resolve a live object reference to our grid, ex. you can fill in something like&#xD;
"This.grdSample". That's the easy part, now how do we use event binding to let us&#xD;
do everything else? &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
I'm going to create a BindControl() method in my custom control and we'll first get&#xD;
our object reference to the grid: &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;font face="Courier New"&gt;loGrid = EVALULATE(This.cGridEval)&lt;/font&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Every grid has a Columns collection that we can iterate through and each column has&#xD;
a Controls collection. If we take a look at the BaseClass property of the controls&#xD;
here we can determine which one is the Header column. At that point we can use BINDEVENT()&#xD;
to hook up the DblClick() event to us - when a user double clicks on this grid column&#xD;
the event will fire on the grid and we'll also get a notification that the event has&#xD;
fired. &#xD;
&lt;/p&gt;&#xD;
        &lt;h6&gt;&#xD;
          &lt;font face="Courier New" size="2"&gt;FOR EACH loColumn IN loGrid.Columns&lt;br&gt;&lt;/font&gt;&#xD;
          &lt;font size="+0"&gt;&#xD;
            &lt;font face="Courier New"&gt;&#xD;
              &lt;font size="2"&gt;   &#xD;
FOR EACH loControl IN loColumn.Controls&lt;br&gt;&#xD;
        IF loControl.BaseClass = "Header"&lt;br&gt;&#xD;
           BINDEVENT(loControl,&#xD;
"DblClick", This, "Sort")&lt;br&gt;&#xD;
           EXIT&lt;br&gt;&#xD;
        ENDIF&lt;br&gt;&#xD;
    ENDFOR&lt;br&gt;&lt;font size="+0"&gt;ENDFOR&lt;/font&gt;&lt;/font&gt;&#xD;
            &lt;/font&gt;&#xD;
          &lt;/font&gt;&#xD;
        &lt;/h6&gt;&#xD;
        &lt;p&gt;&#xD;
The BINDEVENT() function is where the real work happens. We pass the control we want&#xD;
to listen to as the first parameter, in this case the header. Then we pass (as a string)&#xD;
the name of the method we want to listen to, "DblClick". The third parameter is an&#xD;
object reference to the subscribing object (us), and the fourth is the method VFP&#xD;
should call on our object. You must make sure that the method you create on your subscriber&#xD;
accepts all of the same parameters as the event being fired. For example, if we hooked&#xD;
into the KeyPress event accepts two parameters, nKeyCode and nShiftAltCtrl - you have&#xD;
to accept the same parameters in your subscribing method. There is a fifth parameter&#xD;
which can be passed that we're not using which allows you to specify when your code&#xD;
is called - before or after the original control's method fires. DblClick doesn't&#xD;
pass in any parameters, so we're good. All we need to do is create a "Sort" method&#xD;
on our custom object. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
At this point, when a user double clicks on a header in a hooked up grid, our Sort&#xD;
event fires. Great - now how do we figure out which header was clicked on? Here's&#xD;
where the AEVENTS() function comes into play - it fills an array with information&#xD;
about the object that triggered the event. We can use this information to get a reference&#xD;
to the actual header the user double clicked on. From there, we can determine which&#xD;
column in the grid to sort. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;font face="Courier New" size="2"&gt;AEVENTS(laEvent, 0)&lt;/font&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
This gives us a 3 column array, laEvent: &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
laEvent[1] - An object reference to the header that was clicked&lt;br&gt;&#xD;
laEvent[2] - The event that was fired&lt;br&gt;&#xD;
laEvent[3] - The event type (how the event was raised). &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
In our case we're really only interested in laEvent[1]. Once we have our header reference&#xD;
we can get the column's control source like this: &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;font face="Courier New" size="2"&gt;loHeader = laEvent[1]&lt;br&gt;&#xD;
loColumn = loHeader.Parent&lt;br&gt;&#xD;
lcControlSource = ALLTRIM(loColumn.ControlSource)&lt;/font&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
All that's left is for us to build up a way of creating temporarily indexes and maintaining&#xD;
a list of which indexes have been created (and whether we're current ascending or&#xD;
descending). One thing that is kind of nice is that since we now have a reference&#xD;
to the column header, we can also do things like add some graphical image to the sorted&#xD;
column to make it easy for the user to see which column has been sorted and in which&#xD;
direction. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
You'll notice that I didn't cover the UNBINDEVENTS() and RAISEEVENT() functions. UNBINDEVENTS&#xD;
does just what you'd expect - it unhooks an event handler so that it no longer receives&#xD;
the bound event. RAISEVENT() lets you "fire" an event (both things like custom events&#xD;
and events on native VFP objects). I don't have a nice example of this so I'll leave&#xD;
that for some other time. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
You can download the finished control below. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Links:&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;&#xD;
            &lt;a href="http://www.rcs-solutions.com/Download.ashx?File=rcsGridSort.zip"&gt;http://www.rcs-solutions.com/Download.ashx?File=rcsGridSort.zip&lt;/a&gt;&#xD;
          &lt;/strong&gt;&#xD;
          &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=867b838c-c775-4fed-a27b-a7ef42206e36"&gt;&lt;/img&gt;&#xD;
        &lt;/p&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=fYcotJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=fYcotJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=CJgvfJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=CJgvfJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=MSFbPj"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=MSFbPj" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=Z4n2Jj"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=Z4n2Jj" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=c2iTyJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=c2iTyJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,867b838c-c775-4fed-a27b-a7ef42206e36.aspx</comments>
      <category>VFP</category>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/07/31/SortingTheVFPGrid.aspx</feedburner:origLink></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>
      
      <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://feeds.feedburner.com/~r/PaulMrozowski/~3/333562083/WhatIsDependencyInjection.aspx</link>
      <pubDate>Sat, 12 Jul 2008 14:34:13 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
I mentioned Dependency Injection / Inversion of Control (DI/IoC) recently and I really&#xD;
didn't explain what it is, why you might want to use this particular pattern, and&#xD;
why on earth you'd need a framework for it. It's a fancy name for a fairly simple&#xD;
concept. Instead of creating objects inside of your classes, you let the calling code&#xD;
"inject" the necessary instances into your code. It's probably easiest to see this&#xD;
in some code. I'm going to show both C# and VFP code, since I don't want you to get&#xD;
the idea that this is a .NET-only type thing. &#xD;
&lt;br&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
        &lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   1&lt;/span&gt; &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;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   2&lt;/span&gt; {&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   3&lt;/span&gt;    &lt;span style="color: blue"&gt;public&lt;/span&gt;&lt;span style="color: blue"&gt;string&lt;/span&gt; SayHello()&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   4&lt;/span&gt;    {&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   5&lt;/span&gt;       &lt;span style="color: blue"&gt;return&lt;/span&gt;&lt;span style="background: #e5e5e5"&gt;"Hello"&lt;/span&gt;;&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   6&lt;/span&gt;    }&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   7&lt;/span&gt; }&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   8&lt;/span&gt; &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   9&lt;/span&gt; &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;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   10&lt;/span&gt; {&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   11&lt;/span&gt;    &lt;span style="color: blue"&gt;protected&lt;/span&gt;&lt;span style="color: #2b91af"&gt;SampleDependency&lt;/span&gt; m_depend;&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   12&lt;/span&gt; &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   13&lt;/span&gt;    &lt;span style="color: blue"&gt;public&lt;/span&gt;&lt;span style="color: #2b91af"&gt;SampleDependency&lt;/span&gt; Depend&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   14&lt;/span&gt;    {&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   15&lt;/span&gt;       &lt;span style="color: blue"&gt;set&lt;/span&gt; { &lt;span style="color: blue"&gt;this&lt;/span&gt;.m_depend&#xD;
= &lt;span style="color: blue"&gt;value&lt;/span&gt;; }&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   16&lt;/span&gt;    }&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   17&lt;/span&gt; &#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   18&lt;/span&gt;    &lt;span style="color: blue"&gt;public&lt;/span&gt; Sample(&lt;span style="color: #2b91af"&gt;SampleDependency&lt;/span&gt; depend)&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   19&lt;/span&gt;    {&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   20&lt;/span&gt;      &#xD;
m_depend = depend;&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   21&lt;/span&gt;    }&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;   22&lt;/span&gt; }&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
        &lt;/div&gt;&#xD;
        &lt;div style="font-size: 10pt; background: white; color: black; font-family: consolas, courier new"&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
            &lt;span style="color: #2b91af"&gt;  &lt;/span&gt;    &lt;span style="color: #2b91af"&gt;Sample&lt;/span&gt; sample&#xD;
= &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;());&#xD;
&lt;/p&gt;&#xD;
          &lt;p style="margin: 0px"&gt;&#xD;
 &#xD;
&lt;/p&gt;&#xD;
        &lt;/div&gt;&#xD;
        &lt;b&gt;VFP Version&lt;/b&gt;&#xD;
        &lt;pre style="background: #eeeeee"&gt;DEFINE CLASS SampleDependency AS Session &#xD;
   FUNCTION SayHello() &#xD;
      RETURN "Hello" &#xD;
   ENDFUNC &#xD;
ENDDEFINE &#xD;
&#xD;
DEFINE CLASS Sample AS Session &#xD;
   oDepend = NULL &#xD;
   FUNCTION Init(toDepend) &#xD;
      This.oDepend = toDepend &#xD;
   ENDFUNC &#xD;
ENDDEFINE &#xD;
&#xD;
loSample = CREATEOBJECT("Sample", CREATEOBJECT("SampleDependency"))&lt;/pre&gt;&#xD;
        &lt;pre&gt;&#xD;
        &lt;/pre&gt;&#xD;
        &lt;p&gt;&#xD;
Notice that in both cases, we are passing in the instance we want the class to use&#xD;
instead of letting the class create the instance itself. That's all DI/IoC is. Honest,&#xD;
that's it. This is DI via a constructor (you can also do it via a property setting&#xD;
instead; notice in the sample C# code I created a write-only property which could&#xD;
hold the reference). &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
So the next obvious question is, why? What's wrong with just creating the object inside&#xD;
of the class? &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
One thing DI gives you is the ability to easily swap in different objects. In the&#xD;
C# example, we probably would change the parameter from a specific type to an interface.&#xD;
Now any class which implements that interface can be injected into this class. In&#xD;
VFP, since it's not strongly typed, you can just pass in whatever instance you'd like&#xD;
(it's up to you to make sure it doesn't blow up at runtime by accessing some method&#xD;
or property which isn't on the passed in object). My initial thought after seeing&#xD;
this was, well, can't I just use an abstract factory pattern instead? In an abstract&#xD;
factory you delegate object creation to a "object factory" - usually passing in a&#xD;
name or calling a method which returns the actual instance you'd like to use. This&#xD;
sounds like almost the same thing. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
An abstract factory does let you do that, but it doesn't let you easily do something&#xD;
the DI/IoC pattern does: test your objects. Let's suppose you want to write a test&#xD;
for a class which uses another class to send out an e-mail. You aren't really trying&#xD;
to test sending an e-mail - that's just one of the things the class you're testing&#xD;
happens to do during some process. In fact, you really don't want to send out an e-mail;&#xD;
we don't want to spam our users. If you happen to use the abstract factory pattern,&#xD;
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&#xD;
for sending an e-mail (in VFP that's most likely by editing a record in a table, but&#xD;
the idea is the same), then test the object in question. If you used the DI/IoC pattern&#xD;
the only thing you need to do is pass in your dummy/stub/mock object. No other modifications&#xD;
are necessary. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
OK, so this all looks simple enough. Why would you need a framework for the above?!&#xD;
One of the biggest reasons - less typing. You'll notice that in order to use any of&#xD;
these objects you may have to pass in a bunch of other dependency objects (which themselves&#xD;
may have other dependencies). For a complex set of objects that could really suck.&#xD;
A DI framework does that for you along with the benefits of an abstract factory, all&#xD;
rolled up into one. In your code you call the DI framework and tell it to get you&#xD;
an instance of a class - it figures out what objects need to be passed in for you&#xD;
so you don't need to do it. In your tests, you can instanciate the objects directly&#xD;
and pass in your stub/dummy/mock objects instead. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Links:&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &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;&#xD;
          &lt;br&gt;&#xD;
          &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;&#xD;
        &lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=f209f8c4-6087-41cb-b876-ff349f42e8e2"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=eBMlNJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=eBMlNJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=cvb6GJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=cvb6GJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=nmmJWj"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=nmmJWj" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=dgGFQj"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=dgGFQj" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=bsbL7J"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=bsbL7J" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&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>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/07/12/WhatIsDependencyInjection.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.rcs-solutions.com/blog/Trackback.aspx?guid=a375f885-e94d-400e-a8df-1222eafe586e</trackback:ping>
      <pingback:server>http://www.rcs-solutions.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.rcs-solutions.com/blog/PermaLink,guid,a375f885-e94d-400e-a8df-1222eafe586e.aspx</pingback:target>
      <dc:creator>Paul Mrozowski</dc:creator>
      <wfw:comment>http://www.rcs-solutions.com/blog/CommentView,guid,a375f885-e94d-400e-a8df-1222eafe586e.aspx</wfw:comment>
      <wfw:commentRss>http://www.rcs-solutions.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=a375f885-e94d-400e-a8df-1222eafe586e</wfw:commentRss>
      
      <title>MSDN on a diet</title>
      <guid isPermaLink="false">http://www.rcs-solutions.com/blog/PermaLink,guid,a375f885-e94d-400e-a8df-1222eafe586e.aspx</guid>
      <link>http://feeds.feedburner.com/~r/PaulMrozowski/~3/333146380/MSDNOnADiet.aspx</link>
      <pubDate>Sat, 12 Jul 2008 00:42:02 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
I just ran across this and it's a welcome option - you can add "(loband)" to any of&#xD;
the MSDN documentation links on the website and it will serve up a much faster version&#xD;
of the docs. For example,&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Instead of:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a title="http://msdn.microsoft.com/en-us/library/cc707819.aspx" href="http://msdn.microsoft.com/en-us/library/cc707819.aspx"&gt;http://msdn.microsoft.com/en-us/library/cc707819.aspx&lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Try:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a title="http://msdn.microsoft.com/en-us/library/cc707819.aspx" href="http://msdn.microsoft.com/en-us/library/cc707819(loband).aspx"&gt;http://msdn.microsoft.com/en-us/library/cc707819(loband).aspx&lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
There is also an option at the top of the page once you've selected this option to&#xD;
persist the low bandwidth view, so all of the pages come up like this by default.&#xD;
I appreciate the treeview when I'm just poking around, but sometimes the site is just&#xD;
painful to navigate to since it takes a bit to render them. &#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=a375f885-e94d-400e-a8df-1222eafe586e"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=xuV3oJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=xuV3oJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=sF1BIJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=sF1BIJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=RDVMXj"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=RDVMXj" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=teLUcj"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=teLUcj" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=sc4hTJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=sc4hTJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
      <comments>http://www.rcs-solutions.com/blog/CommentView,guid,a375f885-e94d-400e-a8df-1222eafe586e.aspx</comments>
      <category>MSDN</category>
    <feedburner:origLink>http://www.rcs-solutions.com/blog/2008/07/12/MSDNOnADiet.aspx</feedburner:origLink></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>
      
      <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://feeds.feedburner.com/~r/PaulMrozowski/~3/328150321/DayOfNETLansing.aspx</link>
      <pubDate>Sun, 06 Jul 2008 16:24:59 GMT</pubDate>
      <description>&#xD;
        &lt;p&gt;&#xD;
I attended a &lt;a href="http://www.dayofdotnet.org/Lansing/2008/" target="_blank"&gt;Day&#xD;
of Dot Net&lt;/a&gt; event in Lansing a few week back. If you're not familiar with them,&#xD;
they are free mini-conferences (one day) about, not surprisingly, .NET. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
I had originally planned on driving out to it Saturday morning, but then Jenn pointed&#xD;
out I'd have to get up really early to get there around 8am. I already work in Farmington,&#xD;
which is 45 minutes to 1 hour from home (and 45 minutes to 1 hour closer to Lansing)&#xD;
and would end up being a really long day for me. So I ended up just staying at a hotel&#xD;
in Lansing Friday night. That turned out to be a great idea. Note to self: the Best&#xD;
Western in Lansing feels and smells like a 80's style bowling alley.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
When I got to the hotel, I had some time to look up directions to the college where&#xD;
it was being held. It was only a few miles away, so I decided to not bother to drive&#xD;
over there on Friday night (which is what I would normally have done). In the morning&#xD;
I followed the directions Google Maps had given and found myself in a church parking&#xD;
lot (hmm..."Day of Dot Net and Evangelical Revival??"). I checked the map a few times&#xD;
and it looked OK, and I was exactly where it said I should be. I think that was about&#xD;
the point where I starting cursing out Google maps. I had left all my information&#xD;
about the conference in the trunk so I had to get out of the car to get at it. I happened&#xD;
to notice that the road I was on looked like it actually continued around the side&#xD;
of the church (imagine a light bulb going off above my head: "hey...maybe...."). I&#xD;
jumped back in the car and drove around the parking lot and sure enough, the trees&#xD;
suddenly cleared on my left hand side where the college was hiding. I noticed another&#xD;
car stop right about where I stopped, so it wasn't just me being dense (honest!).&#xD;
Note to organizers - great event, but a small sign would have been appreciated. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
When I got into the building (which also wasn't marked, so I still wasn't entirely&#xD;
sure I was at the right entrance), I was surprised at how few people were there -&#xD;
that kind of surprised me since I wasn't able to make it to the last DoDN because&#xD;
it had filled up. It turns out that as the morning wore on the sessions really started&#xD;
to fill up. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
The sessions were an hour long - which is REALLY short; they flew by. The sessions&#xD;
all seemed to run a few minutes long which pushed into the next session running a&#xD;
bit longer. The lunch break helped to reset everything. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
A few notes to the various presenters:&#xD;
&lt;/p&gt;&#xD;
        &lt;ul&gt;&#xD;
          &lt;li&gt;&#xD;
The bottom 1/3 of the screen really isn't visible if you're sitting in the back of&#xD;
the room. I was sitting in the second row and couldn't read some of it. &#xD;
&lt;/li&gt;&#xD;
          &lt;li&gt;&#xD;
White text on a black background might be easier on your eyes for development, but&#xD;
it's impossible to read when it's projected up on a screen. I'd suggest sticking with&#xD;
black text on a white background. &#xD;
&lt;/li&gt;&#xD;
          &lt;li&gt;&#xD;
Don't try to wing demo's. Only a few people can successfully pull that off - you're&#xD;
probably not one of them. &#xD;
&lt;/li&gt;&#xD;
        &lt;/ul&gt;&#xD;
        &lt;p&gt;&#xD;
I actually ran into a few people I knew - one was someone from the local VFP user&#xD;
group, the other was a old-VFP developer that I haven't seen in a few years. That&#xD;
was a nice surprise. Overall, I was impressed by the number of people who attended,&#xD;
considering you're basically giving up a weekend day to attend. It's nice to see that&#xD;
some people actually care about getting better as developers (either that or they,&#xD;
like me, needed a few new shirts for their wardrobe).&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
One session happened to stand out in my mind - a session about Dependency Injection&#xD;
/ Inversion of Control (specifically, the Windsor framework) by &lt;a href="http://jrwren.wrenfam.com/blog/" target="_blank"&gt;Jay&#xD;
Wren&lt;/a&gt;. Well organized, hit every question I had about DI/IoC. Honestly, I didn't&#xD;
"get" DI/IoC before this session; yeah, I understood what it was, but not really why&#xD;
on earth I might need a framework for it. It is actually an elegant way of solving&#xD;
a particular development problem, giving you the benefits of a factory pattern and&#xD;
the flexibility of DI, without getting in your way (at least that's what my notes&#xD;
say). I had the "a ha!" moment, then promptly lost it in one of the other sessions.&#xD;
I'm sure it will come to me at some point, although at this point I'm getting a bit&#xD;
nervous ;-)&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
At the end of the conference, they ended up giving away of ton of stuff. Just not&#xD;
to me. Oh well, maybe next time.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Overall, I definitely attend another one - a big thanks to the organizers and presenters&#xD;
and sponsors, I know it's a lot of work to put something like this on - it was appreciated.&#xD;
Just try to make sure you've got some soft drinks (Coke, Mt. Dew, etc.) available&#xD;
in the morning next time around &amp;lt;g&amp;gt;. It's hard for some of us to get moving&#xD;
in the morning without some caffeine (for us non-coffee drinkers). Sure I feel all&#xD;
healthy from the orange juice I ended up drinking, but it didn't help much to put&#xD;
a spring in my step.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;Links&lt;/strong&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.dayofdotnet.org/Lansing/2008/" target="_blank"&gt;http://www.dayofdotnet.org/Lansing/2008/&lt;/a&gt;&#xD;
          &lt;br&gt;&#xD;
          &lt;a href="http://jrwren.wrenfam.com/blog/" target="_blank"&gt;http://jrwren.wrenfam.com/blog/&lt;/a&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.rcs-solutions.com/blog/aggbug.ashx?id=25546f15-666b-4ef6-8c95-6f002f77732f"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=zOuPWJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=zOuPWJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=5xblyJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=5xblyJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=0zvxrj"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=0zvxrj" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=giaGyj"&gt;&lt;img src="http://feeds.feedburner.com/~f/PaulMrozowski?i=giaGyj" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/PaulMrozowski?a=ZLeBsJ"&gt;&lt;img src="http://feeds.feedburner.com/~f