<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" version="2.0">
  <channel>
    <title>Samurai Programmer.com - Development</title>
    <link>http://www.samuraiprogrammer.com/blog/</link>
    <description>I know kung fu</description>
    <language>en-us</language>
    <copyright>Greg Varveris</copyright>
    <lastBuildDate>Mon, 11 Oct 2010 05:09:42 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.3.9074.18820</generator>
    <managingEditor>greg@samuraiprogrammer.com</managingEditor>
    <webMaster>greg@samuraiprogrammer.com</webMaster>
    <item>
      <trackback:ping>http://www.samuraiprogrammer.com/blog/Trackback.aspx?guid=d439bf53-49be-4b3d-aaec-02ab63e756f3</trackback:ping>
      <pingback:server>http://www.samuraiprogrammer.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.samuraiprogrammer.com/blog/PermaLink,guid,d439bf53-49be-4b3d-aaec-02ab63e756f3.aspx</pingback:target>
      <dc:creator>Greg Varveris</dc:creator>
      <wfw:comment>http://www.samuraiprogrammer.com/blog/CommentView,guid,d439bf53-49be-4b3d-aaec-02ab63e756f3.aspx</wfw:comment>
      <wfw:commentRss>http://www.samuraiprogrammer.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=d439bf53-49be-4b3d-aaec-02ab63e756f3</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/2010/10/04/PivotingASPNETEventLogErrorMessages.aspx">In
my previous post</a>, I added to my series of entries on making sense of your ASP.NET
event log error messages.  Note that this is entry #4 in this series.  The
previous three entries can be found here:
</p>
        <ul>
          <li>
Part 1:  <a href="http://www.samuraiprogrammer.com/blog/ct.ashx?id=a7f8712d-020c-4cd3-acf3-8342ddc1e629&amp;url=http%3a%2f%2fwww.samuraiprogrammer.com%2fblog%2f2010%2f08%2f29%2fParsingASPNETEventLogErrorMessagesForFunAndProfit.aspx">Parsing
ASP.NET event log error messages for fun and profit</a></li>
          <li>
Part 2:  <a href="http://www.samuraiprogrammer.com/blog/ct.ashx?id=a7f8712d-020c-4cd3-acf3-8342ddc1e629&amp;url=http%3a%2f%2fwww.samuraiprogrammer.com%2fblog%2f2010%2f09%2f19%2fDontGuessWhenItComesToPerformanceaRegExStory.aspx">Don’t
guess when it comes to performance…</a></li>
          <li>
Part 3:  <a href="http://www.samuraiprogrammer.com/blog/2010/10/04/PivotingASPNETEventLogErrorMessages.aspx">Pivoting
your ASP.NET event log error messages</a></li>
        </ul>
        <p>
In that last post, I walked through the PAuthorLib.dll and showed you how to crawl
through your event log error messages and create a pivot collection.  The result
of that initial effort was a nice view into our events:
</p>
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/ct.ashx?id=a7f8712d-020c-4cd3-acf3-8342ddc1e629&amp;url=http%3a%2f%2fwww.samuraiprogrammer.com%2fblog%2fcontent%2fbinary%2fWindows-Live-Writer%2f01d5145cc9d9_135BB%2fimage_12.png">
            <img title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb_5.png" width="487" height="377" />
          </a>
        </p>
        <p>
While this certainly got the job done and is a <strong>very </strong>powerful and
compelling view into our data, we need to realize that as our data grow, the amount
of entries in our linked collection is limited.  <a href="http://www.getpivot.com/developer-info/">From
the Developer Overview</a>, we see that the maximum number of items we should have
in a single collection is <strong>3,000</strong>:<strong></strong></p>
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_6.png">
            <img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_thumb_2.png" width="551" height="320" />
          </a>
        </p>
        <p>
So, while a simple collection will get the job done for your smaller amounts of data,
you will really run into some challenges with your larger datasets like our ASP.NET
event log error messages.  To combat this limitation you can create what’s called
a Linked Collection.  The idea is that it’s just a way for you to link together
related collections in order to provide a seamless experience for your users. 
In our case, a natural break for our collections will be based upon the exception
type with a summary collection and then a separate collection for each exception type. 
If I were to draw this out:  
</p>
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/PivotCollections_2.png">
            <img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="PivotCollections" border="0" alt="PivotCollections" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/PivotCollections_thumb.png" width="541" height="204" />
          </a>
        </p>
        <h3>Event Log Header Collection Source
</h3>
        <p>
The idea behind this structure is that the Exception summary would simply link to
each of these exception collections.  First, we’ll create a colleciton source
for our exception summary.  <a href="http://www.samuraiprogrammer.com/blog/2010/10/04/PivotingASPNETEventLogErrorMessages.aspx">As
in our previous collection source (in my last blog post)</a>, we inherit from the
AbstractCollectionSource class and use the LoadHeaderData() method to add our facet
categories to the collection.  In this case, we’ll create two categories – the
number of Occurrences and the Urls where the exception occurred.  Another difference
is that we are going to pass the already parsed collection of messages into the constructor. 
The reason for that is so we don’t have to repeat the parsing of the event log messages
multiple times.
</p>
        <pre class="c#" name="code">class EventLogHeaderCollectionSource : AbstractCollectionSource<br />
{<br /><br />
private IEnumerable&lt;EventLogMessage&gt; m_messages = null;<br /><br />
public EventLogHeaderCollectionSource(IEnumerable&lt;EventLogMessage&gt; messages, 
<br />
string inputFile)<br />
: base(inputFile)<br />
{<br /><br />
m_messages = messages;<br /><br /><br />
}<br /><br />
#region Facets<br /><br />
private const string OCCURRENCES = "Occurrences";<br />
private const string URLS = "Urls";<br /><br />
#endregion<br /><br />
protected override void LoadHeaderData()<br />
{<br />
this.CachedCollectionData.FacetCategories.<br />
Add(new PivotFacetCategory(OCCURRENCES, PivotFacetType.Number));<br />
this.CachedCollectionData.FacetCategories.<br />
Add(new PivotFacetCategory(URLS, PivotFacetType.String));<br /><br />
this.CachedCollectionData.Name = 
<br />
"ASP.NET Error Messages - Summary";<br />
this.CachedCollectionData.Copyright = 
<br />
new PivotLink("Source", "http://www.samuraiprogrammer.com");<br /><br />
}<br />
}</pre>
        <p>
Then, in the LoadItems() method, we provide the logic to generate the PivotItem collection. 
The one key item to make note of is the use of the <strong>Href </strong>property
of the PivotItem object.  This is where we specify the collection we wish to
link to this item.  Since each of the PivotItems will be a summary of the number
of each exception type – we’ll name the sub-collections by its exception type. 
For example, NullReferenceException.cxml, SqlException.cxml, etc.
</p>
        <pre class="c#" name="code">protected override IEnumerable&lt;PivotItem&gt; LoadItems()<br />
{<br />
var results = from log in m_messages<br />
group log by log.Exceptiontype into l<br />
orderby l.Count() descending, l.Key<br />
select new<br />
{<br />
ExceptionType = l.Key,<br />
ExceptionCount = l.Count()<br />
};<br /><br /><br />
int index = 0;<br />
foreach (var result in results)<br />
{<br />
PivotItem item = new PivotItem(index.ToString(), this); 
<br />
item.Name = result.ExceptionType;<br />
item.Description = "# of Exceptions: " + result.ExceptionCount.ToString();<br />
item.AddFacetValues(OCCURRENCES, result.ExceptionCount);<br />
item.Href = result.ExceptionType + ".cxml";<br /><br />
... 
<br /><br />
index++;<br />
yield return item;<br />
}<br /><br />
yield break;<br />
}</pre>
        <h3>Event Log Collection Source Redux
</h3>
        <p>
Previously, when we generated the pivot collections, we were outputting all of the
records into a single collection.  Now that we are generating a collection for
each exception type, we will need to put a filter in our exception collection and
then incorporate that filter into our item generation.  Other than that, the
code we wrote previously remains largely unchanged, so I left the majority of it out
and only included the snippets that we care about below.
</p>
        <pre class="c#" name="code">class EventLogCollectionSource : AbstractCollectionSource<br />
{<br />
private IEnumerable&lt;EventLogMessage&gt; m_messages = null;<br />
private string m_exceptionType = string.Empty;<br /><br />
public EventLogCollectionSource(<br />
IEnumerable&lt;EventLogMessage&gt; messages, 
<br />
string exceptionType, 
<br />
string path)<br />
: base(path)<br />
{<br />
m_messages = messages;<br />
m_exceptionType = exceptionType;<br />
}<br /><br />
protected override void LoadHeaderData()<br />
{<br />
...<br />
this.CachedCollectionData.Name = 
<br />
string.Format("{0} Error Messages", m_exceptionType);<br />
...<br />
}<br /><br />
protected override IEnumerable&lt;PivotItem&gt; LoadItems()<br />
{<br />
var results = (from message in m_messages<br />
where message.Exceptiontype == m_exceptionType<br />
select message);<br /><br />
int index = 0;<br />
foreach (EventLogMessage message in results)<br />
{<br />
PivotItem item = 
<br />
new PivotItem(index.ToString(), this);<br />
item.Name = message.Exceptiontype;<br />
item.Description = message.Exceptionmessage;<br /><br />
...<br /><br />
index++;<br />
yield return item;<br />
}<br />
yield break;<br />
}<br />
}</pre>
        <h3>Generate and test the collection
</h3>
        <p>
Then, the only thing we have left to do is generate and test our linked collections. 
I won’t go into a lengthy explanation of how we generate the collections because <a href="http://www.samuraiprogrammer.com/blog/2010/10/04/PivotingASPNETEventLogErrorMessages.aspx">I
did that in the last blog entry</a>.  I will show the broad strokes required
to tie this all together, though:
</p>
        <pre class="c#" name="code">// Load the raw messages into a collection<br />
IEnumerable&lt;EventLogMessage&gt; messages = 
<br />
LoadEventLogMessages(inputFile).ToList();<br /><br />
// Generate summary pivot collection<br />
EventLogHeaderCollectionSource sourceSummary = 
<br />
new EventLogHeaderCollectionSource(messages, inputFile);<br />
...<br />
summaryTargetFilter1.Write(sourceSummaryFilter1);<br /><br />
// Get the aggregate results so we know the filters<br />
// for our exception pivot collections<br />
var summaryResults = from log in messages<br />
group log by log.Exceptiontype into l<br />
orderby l.Count() descending, l.Key<br />
select new<br />
{<br />
ExceptionType = l.Key,<br />
ExceptionCount = l.Count()<br />
};<br /><br />
foreach (var resultItem in summaryResults)<br />
{<br />
// Generate pivots for each exception type<br />
EventLogCollectionSource source = 
<br />
new EventLogCollectionSource(messages, 
<br />
resultItem.ExceptionType, 
<br />
inputFile);<br />
...<br />
targetFilter1.Write(sourceFilter1);<br />
}</pre>
        <p>
Once we we have this code and everything has been generated, if we open the output
folder, we’ll see the following structure:
</p>
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_8.png">
            <img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_thumb_3.png" width="515" height="387" />
          </a>
        </p>
        <p>
We see our ExceptionSummary pivot collection and all of the deep zoom folders. 
So, when we open the Pivot tool, we’ll see a nice parent collection:
</p>
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_10.png">
            <img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_thumb_4.png" width="644" height="407" />
          </a>
        </p>
        <p>
This gives us a nice breakdown of the number of occurrences for each exception in
our source data.  Immediately we see an outlier (more on that later) between
the 6,000 and 7,000 item mark and when we select that tile, we see the following:
</p>
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_12.png">
            <img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_thumb_5.png" width="644" height="440" />
          </a>
        </p>
        <p>
We also see a green “Open” box (surrounded in a red rectangle, my emphasis) which
links to our NullReferenceException.cxml.  When we click that box, the tool will
immediately open that collection in the UI for our perusal – providing a very similar
look to what we saw in the last entry:
</p>
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_14.png">
            <img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_thumb_6.png" width="644" height="377" />
          </a>
        </p>
        <h3>Closing Thoughts
</h3>
        <p>
Now, you may have noticed a contradiction above.  I said that a collection should
have no more than 3,000 items and yet, with the NullReferenceException collection,
we saw in the summary that it had over 6,000 items.  That is a very good point
and will be a subject of a future blog post.  I wanted to illustrate the simple
collections and the linked collections before we got into that third type of collection
from above – the Dynamic Collection.  Stay tuned!
</p>
      </body>
      <title>Linking your pivot collections the fun and easy way</title>
      <guid isPermaLink="false">http://www.samuraiprogrammer.com/blog/PermaLink,guid,d439bf53-49be-4b3d-aaec-02ab63e756f3.aspx</guid>
      <link>http://www.samuraiprogrammer.com/blog/2010/10/11/LinkingYourPivotCollectionsTheFunAndEasyWay.aspx</link>
      <pubDate>Mon, 11 Oct 2010 05:09:42 GMT</pubDate>
      <description>&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/2010/10/04/PivotingASPNETEventLogErrorMessages.aspx"&gt;In
my previous post&lt;/a&gt;, I added to my series of entries on making sense of your ASP.NET
event log error messages.&amp;#160; Note that this is entry #4 in this series.&amp;#160; The
previous three entries can be found here:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Part 1:&amp;#160; &lt;a href="http://www.samuraiprogrammer.com/blog/ct.ashx?id=a7f8712d-020c-4cd3-acf3-8342ddc1e629&amp;amp;url=http%3a%2f%2fwww.samuraiprogrammer.com%2fblog%2f2010%2f08%2f29%2fParsingASPNETEventLogErrorMessagesForFunAndProfit.aspx"&gt;Parsing
ASP.NET event log error messages for fun and profit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
Part 2:&amp;#160; &lt;a href="http://www.samuraiprogrammer.com/blog/ct.ashx?id=a7f8712d-020c-4cd3-acf3-8342ddc1e629&amp;amp;url=http%3a%2f%2fwww.samuraiprogrammer.com%2fblog%2f2010%2f09%2f19%2fDontGuessWhenItComesToPerformanceaRegExStory.aspx"&gt;Don’t
guess when it comes to performance…&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
Part 3:&amp;#160; &lt;a href="http://www.samuraiprogrammer.com/blog/2010/10/04/PivotingASPNETEventLogErrorMessages.aspx"&gt;Pivoting
your ASP.NET event log error messages&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
In that last post, I walked through the PAuthorLib.dll and showed you how to crawl
through your event log error messages and create a pivot collection.&amp;#160; The result
of that initial effort was a nice view into our events:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/ct.ashx?id=a7f8712d-020c-4cd3-acf3-8342ddc1e629&amp;amp;url=http%3a%2f%2fwww.samuraiprogrammer.com%2fblog%2fcontent%2fbinary%2fWindows-Live-Writer%2f01d5145cc9d9_135BB%2fimage_12.png"&gt;&lt;img title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb_5.png" width="487" height="377" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
While this certainly got the job done and is a &lt;strong&gt;very &lt;/strong&gt;powerful and
compelling view into our data, we need to realize that as our data grow, the amount
of entries in our linked collection is limited.&amp;#160; &lt;a href="http://www.getpivot.com/developer-info/"&gt;From
the Developer Overview&lt;/a&gt;, we see that the maximum number of items we should have
in a single collection is &lt;strong&gt;3,000&lt;/strong&gt;:&lt;strong&gt; &lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_6.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_thumb_2.png" width="551" height="320" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
So, while a simple collection will get the job done for your smaller amounts of data,
you will really run into some challenges with your larger datasets like our ASP.NET
event log error messages.&amp;#160; To combat this limitation you can create what’s called
a Linked Collection.&amp;#160; The idea is that it’s just a way for you to link together
related collections in order to provide a seamless experience for your users.&amp;#160;
In our case, a natural break for our collections will be based upon the exception
type with a summary collection and then a separate collection for each exception type.&amp;#160;
If I were to draw this out:&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/PivotCollections_2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="PivotCollections" border="0" alt="PivotCollections" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/PivotCollections_thumb.png" width="541" height="204" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;h3&gt;Event Log Header Collection Source
&lt;/h3&gt;
&lt;p&gt;
The idea behind this structure is that the Exception summary would simply link to
each of these exception collections.&amp;#160; First, we’ll create a colleciton source
for our exception summary.&amp;#160; &lt;a href="http://www.samuraiprogrammer.com/blog/2010/10/04/PivotingASPNETEventLogErrorMessages.aspx"&gt;As
in our previous collection source (in my last blog post)&lt;/a&gt;, we inherit from the
AbstractCollectionSource class and use the LoadHeaderData() method to add our facet
categories to the collection.&amp;#160; In this case, we’ll create two categories – the
number of Occurrences and the Urls where the exception occurred.&amp;#160; Another difference
is that we are going to pass the already parsed collection of messages into the constructor.&amp;#160;
The reason for that is so we don’t have to repeat the parsing of the event log messages
multiple times.
&lt;/p&gt;
&lt;pre class="c#" name="code"&gt;class EventLogHeaderCollectionSource : AbstractCollectionSource&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
private IEnumerable&amp;lt;EventLogMessage&amp;gt; m_messages = null;&lt;br /&gt;
&lt;br /&gt;
public EventLogHeaderCollectionSource(IEnumerable&amp;lt;EventLogMessage&amp;gt; messages, 
&lt;br /&gt;
string inputFile)&lt;br /&gt;
: base(inputFile)&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
m_messages = messages;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#region Facets&lt;br /&gt;
&lt;br /&gt;
private const string OCCURRENCES = &amp;quot;Occurrences&amp;quot;;&lt;br /&gt;
private const string URLS = &amp;quot;Urls&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
#endregion&lt;br /&gt;
&lt;br /&gt;
protected override void LoadHeaderData()&lt;br /&gt;
{&lt;br /&gt;
this.CachedCollectionData.FacetCategories.&lt;br /&gt;
Add(new PivotFacetCategory(OCCURRENCES, PivotFacetType.Number));&lt;br /&gt;
this.CachedCollectionData.FacetCategories.&lt;br /&gt;
Add(new PivotFacetCategory(URLS, PivotFacetType.String));&lt;br /&gt;
&lt;br /&gt;
this.CachedCollectionData.Name = 
&lt;br /&gt;
&amp;quot;ASP.NET Error Messages - Summary&amp;quot;;&lt;br /&gt;
this.CachedCollectionData.Copyright = 
&lt;br /&gt;
new PivotLink(&amp;quot;Source&amp;quot;, &amp;quot;http://www.samuraiprogrammer.com&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
}&lt;/pre&gt;
&lt;p&gt;
Then, in the LoadItems() method, we provide the logic to generate the PivotItem collection.&amp;#160;
The one key item to make note of is the use of the &lt;strong&gt;Href &lt;/strong&gt;property
of the PivotItem object.&amp;#160; This is where we specify the collection we wish to
link to this item.&amp;#160; Since each of the PivotItems will be a summary of the number
of each exception type – we’ll name the sub-collections by its exception type.&amp;#160;
For example, NullReferenceException.cxml, SqlException.cxml, etc.
&lt;/p&gt;
&lt;pre class="c#" name="code"&gt;protected override IEnumerable&amp;lt;PivotItem&amp;gt; LoadItems()&lt;br /&gt;
{&lt;br /&gt;
var results = from log in m_messages&lt;br /&gt;
group log by log.Exceptiontype into l&lt;br /&gt;
orderby l.Count() descending, l.Key&lt;br /&gt;
select new&lt;br /&gt;
{&lt;br /&gt;
ExceptionType = l.Key,&lt;br /&gt;
ExceptionCount = l.Count()&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int index = 0;&lt;br /&gt;
foreach (var result in results)&lt;br /&gt;
{&lt;br /&gt;
PivotItem item = new PivotItem(index.ToString(), this); 
&lt;br /&gt;
item.Name = result.ExceptionType;&lt;br /&gt;
item.Description = &amp;quot;# of Exceptions: &amp;quot; + result.ExceptionCount.ToString();&lt;br /&gt;
item.AddFacetValues(OCCURRENCES, result.ExceptionCount);&lt;br /&gt;
item.Href = result.ExceptionType + &amp;quot;.cxml&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
... 
&lt;br /&gt;
&lt;br /&gt;
index++;&lt;br /&gt;
yield return item;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
yield break;&lt;br /&gt;
}&lt;/pre&gt;
&lt;h3&gt;Event Log Collection Source Redux
&lt;/h3&gt;
&lt;p&gt;
Previously, when we generated the pivot collections, we were outputting all of the
records into a single collection.&amp;#160; Now that we are generating a collection for
each exception type, we will need to put a filter in our exception collection and
then incorporate that filter into our item generation.&amp;#160; Other than that, the
code we wrote previously remains largely unchanged, so I left the majority of it out
and only included the snippets that we care about below.
&lt;/p&gt;
&lt;pre class="c#" name="code"&gt;class EventLogCollectionSource : AbstractCollectionSource&lt;br /&gt;
{&lt;br /&gt;
private IEnumerable&amp;lt;EventLogMessage&amp;gt; m_messages = null;&lt;br /&gt;
private string m_exceptionType = string.Empty;&lt;br /&gt;
&lt;br /&gt;
public EventLogCollectionSource(&lt;br /&gt;
IEnumerable&amp;lt;EventLogMessage&amp;gt; messages, 
&lt;br /&gt;
string exceptionType, 
&lt;br /&gt;
string path)&lt;br /&gt;
: base(path)&lt;br /&gt;
{&lt;br /&gt;
m_messages = messages;&lt;br /&gt;
m_exceptionType = exceptionType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
protected override void LoadHeaderData()&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
this.CachedCollectionData.Name = 
&lt;br /&gt;
string.Format(&amp;quot;{0} Error Messages&amp;quot;, m_exceptionType);&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
protected override IEnumerable&amp;lt;PivotItem&amp;gt; LoadItems()&lt;br /&gt;
{&lt;br /&gt;
var results = (from message in m_messages&lt;br /&gt;
where message.Exceptiontype == m_exceptionType&lt;br /&gt;
select message);&lt;br /&gt;
&lt;br /&gt;
int index = 0;&lt;br /&gt;
foreach (EventLogMessage message in results)&lt;br /&gt;
{&lt;br /&gt;
PivotItem item = 
&lt;br /&gt;
new PivotItem(index.ToString(), this);&lt;br /&gt;
item.Name = message.Exceptiontype;&lt;br /&gt;
item.Description = message.Exceptionmessage;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
index++;&lt;br /&gt;
yield return item;&lt;br /&gt;
}&lt;br /&gt;
yield break;&lt;br /&gt;
}&lt;br /&gt;
}&lt;/pre&gt;
&lt;h3&gt;Generate and test the collection
&lt;/h3&gt;
&lt;p&gt;
Then, the only thing we have left to do is generate and test our linked collections.&amp;#160;
I won’t go into a lengthy explanation of how we generate the collections because &lt;a href="http://www.samuraiprogrammer.com/blog/2010/10/04/PivotingASPNETEventLogErrorMessages.aspx"&gt;I
did that in the last blog entry&lt;/a&gt;.&amp;#160; I will show the broad strokes required
to tie this all together, though:
&lt;/p&gt;
&lt;pre class="c#" name="code"&gt;// Load the raw messages into a collection&lt;br /&gt;
IEnumerable&amp;lt;EventLogMessage&amp;gt; messages = 
&lt;br /&gt;
LoadEventLogMessages(inputFile).ToList();&lt;br /&gt;
&lt;br /&gt;
// Generate summary pivot collection&lt;br /&gt;
EventLogHeaderCollectionSource sourceSummary = 
&lt;br /&gt;
new EventLogHeaderCollectionSource(messages, inputFile);&lt;br /&gt;
...&lt;br /&gt;
summaryTargetFilter1.Write(sourceSummaryFilter1);&lt;br /&gt;
&lt;br /&gt;
// Get the aggregate results so we know the filters&lt;br /&gt;
// for our exception pivot collections&lt;br /&gt;
var summaryResults = from log in messages&lt;br /&gt;
group log by log.Exceptiontype into l&lt;br /&gt;
orderby l.Count() descending, l.Key&lt;br /&gt;
select new&lt;br /&gt;
{&lt;br /&gt;
ExceptionType = l.Key,&lt;br /&gt;
ExceptionCount = l.Count()&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
foreach (var resultItem in summaryResults)&lt;br /&gt;
{&lt;br /&gt;
// Generate pivots for each exception type&lt;br /&gt;
EventLogCollectionSource source = 
&lt;br /&gt;
new EventLogCollectionSource(messages, 
&lt;br /&gt;
resultItem.ExceptionType, 
&lt;br /&gt;
inputFile);&lt;br /&gt;
...&lt;br /&gt;
targetFilter1.Write(sourceFilter1);&lt;br /&gt;
}&lt;/pre&gt;
&lt;p&gt;
Once we we have this code and everything has been generated, if we open the output
folder, we’ll see the following structure:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_8.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_thumb_3.png" width="515" height="387" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
We see our ExceptionSummary pivot collection and all of the deep zoom folders.&amp;#160;
So, when we open the Pivot tool, we’ll see a nice parent collection:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_10.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_thumb_4.png" width="644" height="407" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
This gives us a nice breakdown of the number of occurrences for each exception in
our source data.&amp;#160; Immediately we see an outlier (more on that later) between
the 6,000 and 7,000 item mark and when we select that tile, we see the following:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_12.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_thumb_5.png" width="644" height="440" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
We also see a green “Open” box (surrounded in a red rectangle, my emphasis) which
links to our NullReferenceException.cxml.&amp;#160; When we click that box, the tool will
immediately open that collection in the UI for our perusal – providing a very similar
look to what we saw in the last entry:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_14.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/Pivoting-ASP.NET_A224/image_thumb_6.png" width="644" height="377" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;h3&gt;Closing Thoughts
&lt;/h3&gt;
&lt;p&gt;
Now, you may have noticed a contradiction above.&amp;#160; I said that a collection should
have no more than 3,000 items and yet, with the NullReferenceException collection,
we saw in the summary that it had over 6,000 items.&amp;#160; That is a very good point
and will be a subject of a future blog post.&amp;#160; I wanted to illustrate the simple
collections and the linked collections before we got into that third type of collection
from above – the Dynamic Collection.&amp;#160; Stay tuned!
&lt;/p&gt;</description>
      <comments>http://www.samuraiprogrammer.com/blog/CommentView,guid,d439bf53-49be-4b3d-aaec-02ab63e756f3.aspx</comments>
      <category>ASP.NET</category>
      <category>Development</category>
      <category>Pivot</category>
    </item>
    <item>
      <trackback:ping>http://www.samuraiprogrammer.com/blog/Trackback.aspx?guid=a7f8712d-020c-4cd3-acf3-8342ddc1e629</trackback:ping>
      <pingback:server>http://www.samuraiprogrammer.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.samuraiprogrammer.com/blog/PermaLink,guid,a7f8712d-020c-4cd3-acf3-8342ddc1e629.aspx</pingback:target>
      <dc:creator>Greg Varveris</dc:creator>
      <wfw:comment>http://www.samuraiprogrammer.com/blog/CommentView,guid,a7f8712d-020c-4cd3-acf3-8342ddc1e629.aspx</wfw:comment>
      <wfw:commentRss>http://www.samuraiprogrammer.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=a7f8712d-020c-4cd3-acf3-8342ddc1e629</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/logo-pivot_2.png">
            <img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="logo-pivot" border="0" alt="logo-pivot" align="left" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/logo-pivot_thumb.png" width="191" height="80" />
          </a>Unless
you’ve been hiding under the proverbial rock, you’ve probably seen the recent <a href="http://www.getpivot.com/">Pivot
hoopla</a>.  If you’re not familiar with it, it’s a way to visualize a large
amount of data in a nice filterable format.  The nice thing about it is that
it’s really easy to put together a pivot collection and there are a ton of tools available
for just this purpose.  Just do a search on CodePlex for Pivot and you’ll get
about 40’ish good results for tools you can use to create a Pivot Collection.  
</p>
        <p>
So, I was putting together a proof-of-concept for an internal project and thought
I would continue on with my series of blog posts on ASP.NET Error Message event logs
with a post on how to visualize this data using a pivot.  You may wish to read
parts 1 and 2 here:
</p>
        <ul>
          <li>
Part 1:  <a href="http://www.samuraiprogrammer.com/blog/2010/08/29/ParsingASPNETEventLogErrorMessagesForFunAndProfit.aspx">Parsing
ASP.NET event log error messages for fun and profit</a></li>
          <li>
Part 2:  <a href="http://www.samuraiprogrammer.com/blog/2010/09/19/DontGuessWhenItComesToPerformanceaRegExStory.aspx">Don’t
guess when it comes to performance…</a></li>
        </ul>
        <p>
So, when I put together my pivot, I worked out a 3 step process:
</p>
        <ol>
          <li>
Figure out what you want to Pivot</li>
          <li>
Find an API and convert the data</li>
          <li>
Generate and Test the collection</li>
        </ol>
        <p>
Let’s begin, shall we.
</p>
        <h3>
        </h3>
        <h3>Figure out what you want to Pivot
</h3>
        <p>
The structure for the Pivot Collection is deceptively simple - 
</p>
        <pre class="xml" name="code">&lt;?xml version="1.0"?&gt; 
<br />
&lt;Collection Name="Hello World Collection" …&gt;<br />
&lt;FacetCategories&gt; 
<br />
&lt;FacetCategory Name="Hello World Facet Category One" Type="String"/&gt; 
<br />
&lt;/FacetCategories&gt; 
<br />
&lt;Items ImgBase="helloworld.dzc"&gt; 
<br />
&lt;Item Img="#0" Id="0" Href="http://www.getpivot.com"
Name="Hello World!"&gt; 
<br />
&lt;Description&gt; This is the only item in the collection.&lt;/Description&gt; 
<br />
&lt;Facets&gt; 
<br />
&lt;Facet Name="Hello World Facet Category One"&gt; 
<br />
&lt;String Value="Hello World Facet Value"/&gt; 
<br />
&lt;/Facet&gt; 
<br />
&lt;/Facets&gt; 
<br />
&lt;/Item&gt; 
<br />
&lt;/Items&gt; 
<br />
&lt;/Collection&gt;</pre>
        <p>
The way that I think about the Items in the Collection are in the same way that you
might think about an object.  For example, a Car object might have the following
properties:
</p>
        <ul>
          <li>
Advertising blurb</li>
          <li>
Car and Driver Reviews</li>
          <li>
Color</li>
          <li>
Make</li>
          <li>
Model</li>
          <li>
Engine</li>
          <li>
0-60mph time</li>
          <li>
Max Speed</li>
        </ul>
        <p>
The common values like the Color, Make, Model, 0-60mph time and max speed become the
facets or attributes that describe your object in relation to other instances of objects. 
Things like the advertising blurbs and car and driver reviews or descriptions belong
instead as properties of your Item directly in the Description element.
</p>
        <p>
For our data, namely ASP.NET exceptions, we’re going to define an exception as the
following:
</p>
        <ul>
          <li>
Item</li>
          <ul>
            <li>
Name = Exception Type</li>
            <li>
Description = Exception Message</li>
            <li>
Facets</li>
            <ul>
              <li>
Request Path</li>
              <li>
Stack Trace</li>
              <li>
Event Time</li>
              <li>
Top Method of Stack Trace</li>
              <li>
Top My Code Method of Stack Trace</li>
            </ul>
          </ul>
        </ul>
        <p>
This should allow us to group and drill through the common properties that might link
exceptions together and still provide detailed error information when necessary.
</p>
        <h3>Find an API and code it
</h3>
        <p>
The second step here is to find some code/API/tool that we can enhance for our purposes. 
There are some great tools published by the Live Labs team – for example:
</p>
        <ul>
          <li>
            <a href="http://www.getpivot.com/developer-info/download-cmd-tools.aspx">Pivot Collection
Tool for the Command Line</a>
          </li>
          <li>
            <a href="http://www.getpivot.com/developer-info/download-excel-tools.aspx">Pivot Collection
Tool for Microsoft Excel</a>
          </li>
        </ul>
        <p>
While both tools could be used in this instance, in part 2 we found that some of our
Event Logs we were parsing contained more than 10,000 items and I wanted a bit more
control over how I converted the data.  “No touching” is the phrase of the day.  <a href="http://pauthor.codeplex.com/">Fortunately,
the command line tool was published on CodePlex with an API we can use</a>. 
Once you download the product you see that it contains 3 assemblies:
</p>
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_2.png">
            <img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb.png" width="468" height="121" />
          </a>
        </p>
        <p>
The last item there is the PauthorLib.dll which encapsulates many of the extension
points within this great tool.  In-fact, it exposes about 7 different namespaces
for our purposes:
</p>
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_4.png">
            <img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb_1.png" width="301" height="148" />
          </a>
        </p>
        <p>
For our purposes, we are going to focus on the Streaming set of namespaces. 
Why?  Well, this is namely because we are going to be dealing with a lot of data
and I didn’t want to load everything into memory before writing it to disk. 
If you look at the contents of the Streaming namespace, you’ll see a great class called
“AbstractCollectionSource”.  This looks fairly promising because it exposes two
main methods:
</p>
        <pre class="c#" name="code">class EventLogExceptionCollectionSource : AbstractCollectionSource<br />
{<br />
protected override void LoadHeaderData()<br />
{<br />
throw new NotImplementedException();<br />
}<br /><br />
protected override IEnumerable&lt;PivotItem&gt; LoadItems()<br />
{<br />
throw new NotImplementedException();<br />
}<br />
}</pre>
        <p>
Before we do anything, though, we need a constructor.  The constructor will be
responsible for taking a string representing the path to our data and passing it to
our base class’s constructor.
</p>
        <pre class="c#" name="code">public EventLogExceptionCollectionSource(string filePath)<br />
: base(filePath)<br />
{<br /><br />
// Do nothing else.<br /><br />
}</pre>
Then, the first method, LoadHeaderData, is where we define our facets – Request Path,
Stack Trace, etc.  - as well as the data types that each facet will be. 
So, our code will be fairly simple and straight-forward: <pre class="c#" name="code">protected override void LoadHeaderData()<br />
{<br /><br />
this.CachedCollectionData.FacetCategories.Add(<br />
new PivotFacetCategory(STACKTRACE, 
<br />
PivotFacetType.LongString));<br />
this.CachedCollectionData.FacetCategories.Add(<br />
new PivotFacetCategory(REQUESTPATH, 
<br />
PivotFacetType.String));<br />
this.CachedCollectionData.FacetCategories.Add(<br />
new PivotFacetCategory(EVENTTIME, 
<br />
PivotFacetType.DateTime));<br />
this.CachedCollectionData.FacetCategories.Add(<br />
new PivotFacetCategory(TOPMETHOD, 
<br />
PivotFacetType.String));<br />
this.CachedCollectionData.FacetCategories.Add(<br />
new PivotFacetCategory(TOPAPPMETHOD, 
<br />
PivotFacetType.String));<br /><br />
this.CachedCollectionData.Name = "Event Log Error Messages";<br /><br /><br />
}</pre><p>
The second method, LoadItems(), is responsible for doing exactly what it suggests
– this is where we load the data from whichever source we care about and then convert
it into our PivotItem collection.  For our purposes, we’re going to load the
XML file we defined in <a href="http://www.samuraiprogrammer.com/blog/2010/08/29/ParsingASPNETEventLogErrorMessagesForFunAndProfit.aspx">Part
1</a> of this series into a list of EventLogMessage objects and then convert those
EventLogMessage objects into PivotItem objects:
</p><pre class="c#" name="code">protected override IEnumerable&lt;PivotItem&gt; LoadItems()<br />
{<br />
// Load XML file<br />
XDocument document = XDocument.Load(this.BasePath);<br /><br />
// Populate collection of EventLogMessage objects<br />
var messages = from message in document.Descendants("Message")<br />
select EventLogMessage.Load(message.Value);<br /><br />
int index = 0;<br />
foreach (EventLogMessage message in messages)<br />
{<br /><br />
PivotItem item = new PivotItem(index.ToString(), this);<br />
item.Name = message.Exceptiontype;<br />
item.Description = message.Exceptionmessage;<br />
item.AddFacetValues(REQUESTPATH, message.Requestpath);<br />
item.AddFacetValues(STACKTRACE, message.Stacktrace);<br />
item.AddFacetValues(EVENTTIME, message.Eventtime);<br />
item.AddFacetValues(TOPMETHOD, message.StackTraceFrames[0].Method);<br />
item.AddFacetValues(TOPAPPMETHOD, GetFirstNonMicrosoftMethod(message.StackTraceFrames));<br /><br />
index++;<br />
yield return item;<br /><br />
}<br />
}</pre><p>
The key method calls from above are the AddFacetValues(…) method calls.  This
method essentially sets the attributes we wish to have our data pivot upon. 
This, by itself, isn’t enough to generate our great pivot calls – we need to call
our code from somewhere.  Since this is a simple app, we’re going to make it
a console app.  For our Collection to get generated we need to use a few other
objects included in this API:
</p><ul><li><strong>EventLogExceptionCollectionSource</strong> – The class we created above.</li><li><strong>HtmlImageCreationSourceFilter</strong> – This class will generate the tile
in the Pivot based upon some HTML template we specify.</li><li><strong>LocalCxmlCollectionTarget</strong> – Generates the Collection XML file at
the path we specify.</li><li><strong>DeepZoomTargetFilter</strong> – Generates the deep zoom files to support our
collection XML file and also enables all of our fancy transitions.</li></ul><p>
In practice, the code is pretty simple and straight forward and I applaud the people
who wrote this library:
</p><pre class="c#" name="code">private static void GenerateExceptionPivot(string inputFile, string outputFolder)<br />
{<br />
string collectionName = Path.Combine(outputFolder, "MyExceptions.cxml");<br /><br />
EventLogExceptionCollectionSource source = 
<br />
new EventLogExceptionCollectionSource(inputFile);<br />
HtmlImageCreationSourceFilter sourceFilter1 = 
<br />
new HtmlImageCreationSourceFilter(source);<br />
sourceFilter1.HtmlTemplate = 
<br />
"&lt;html&gt;&lt;body&gt;&lt;h1&gt;{name}&lt;/h1&gt;{description}&lt;/body&gt;&lt;/html&gt;";<br />
sourceFilter1.Width = 600;<br />
sourceFilter1.Height = 600;<br /><br />
LocalCxmlCollectionTarget target = 
<br />
new LocalCxmlCollectionTarget(collectionName);<br />
DeepZoomTargetFilter targetFilter1 = 
<br />
new DeepZoomTargetFilter(target);<br />
targetFilter1.Write(sourceFilter1);<br /><br />
}</pre><p>
That last statement, targetFilter1.Write(…) is what will actually execute everything
and write our resultant files to disk.
</p><h3>Generate and Test the collection
</h3><p>
So, now if we run our console application and call that GenerateExceptionPivot(…)
method, we’ll get some great output.
</p><p><a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_6.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb_2.png" width="644" height="361" /></a></p><p>
What’s nice about the Library is that it provides progress as it iterates through
your data (in the red rectangle) and also in the blue rectangle, we need that it’s
multi-threaded by default.  This is primarily for the most intensive part of
the operation – the creation of the deep zoom artifacts.  If you have one of
those new fangled machines with 2+ cores, you can tweak the number of threads that
it will spawn for this operation by setting the ThreadCount property of the DeepZoomTargetFilter
object.  This may or may not improve your performance but it’s nice that the
option is available.
</p><pre class="c#" name="code">...<br />
DeepZoomTargetFilter targetFilter1 = 
<br />
new DeepZoomTargetFilter(target);<br /><br /><font color="#ff0000"><strong>targetFilter1.ThreadCount = 100;<br /></strong></font>targetFilter1.Write(sourceFilter1);<br />
...</pre><p>
Once our collection has been generated, we can browse it in an explorer.exe window
just to get an idea of what our code has wrought:
</p><p><a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_10.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb_4.png" width="640" height="218" /></a></p><p>
And then to test it, you can just point the Live Labs Pivot application at our “MyExceptions.cxml”
file and view the wonderful data.  For example, you can look at the Event Time
in the histogram view to see how your exceptions broke down over time.  You can
also filter your data by things like the RequestPath (the page that threw the exception)
or the Method that was at the top of the callstack.
</p><p><a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_12.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb_5.png" width="626" height="484" /></a></p><p>
Then, you can zoom in on a specific time slice you care about:
</p><p><a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_14.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb_6.png" width="544" height="484" /></a></p><p>
Then, if you want to view the details for a specific instance, just click the corresponding
tile.  Then, a new side bar will appear on the right hand side with all of the
details we stored in this record:
</p><p><a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_16.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb_7.png" width="281" height="429" /></a></p><p>
We generated a single collection in this blog post.  One thing to keep in mind
is that each collection should have no more than 3,000 items.  For collections
in which you want to have more than 3,000 items, you should look at potentially creating
a Linked Collection.  That will be the subject of an upcoming blog post.  
</p><p>
Until next time!
</p></body>
      <title>Pivoting ASP.NET event log error messages</title>
      <guid isPermaLink="false">http://www.samuraiprogrammer.com/blog/PermaLink,guid,a7f8712d-020c-4cd3-acf3-8342ddc1e629.aspx</guid>
      <link>http://www.samuraiprogrammer.com/blog/2010/10/04/PivotingASPNETEventLogErrorMessages.aspx</link>
      <pubDate>Mon, 04 Oct 2010 15:43:49 GMT</pubDate>
      <description>&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/logo-pivot_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 10px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="logo-pivot" border="0" alt="logo-pivot" align="left" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/logo-pivot_thumb.png" width="191" height="80" /&gt;&lt;/a&gt;Unless
you’ve been hiding under the proverbial rock, you’ve probably seen the recent &lt;a href="http://www.getpivot.com/"&gt;Pivot
hoopla&lt;/a&gt;.&amp;#160; If you’re not familiar with it, it’s a way to visualize a large
amount of data in a nice filterable format.&amp;#160; The nice thing about it is that
it’s really easy to put together a pivot collection and there are a ton of tools available
for just this purpose.&amp;#160; Just do a search on CodePlex for Pivot and you’ll get
about 40’ish good results for tools you can use to create a Pivot Collection.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
So, I was putting together a proof-of-concept for an internal project and thought
I would continue on with my series of blog posts on ASP.NET Error Message event logs
with a post on how to visualize this data using a pivot.&amp;#160; You may wish to read
parts 1 and 2 here:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Part 1:&amp;#160; &lt;a href="http://www.samuraiprogrammer.com/blog/2010/08/29/ParsingASPNETEventLogErrorMessagesForFunAndProfit.aspx"&gt;Parsing
ASP.NET event log error messages for fun and profit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
Part 2:&amp;#160; &lt;a href="http://www.samuraiprogrammer.com/blog/2010/09/19/DontGuessWhenItComesToPerformanceaRegExStory.aspx"&gt;Don’t
guess when it comes to performance…&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
So, when I put together my pivot, I worked out a 3 step process:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Figure out what you want to Pivot&lt;/li&gt;
&lt;li&gt;
Find an API and convert the data&lt;/li&gt;
&lt;li&gt;
Generate and Test the collection&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
Let’s begin, shall we.
&lt;/p&gt;
&lt;h3&gt;
&lt;/h3&gt;
&lt;h3&gt;Figure out what you want to Pivot
&lt;/h3&gt;
&lt;p&gt;
The structure for the Pivot Collection is deceptively simple - 
&lt;/p&gt;
&lt;pre class="xml" name="code"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt; 
&lt;br /&gt;
&amp;lt;Collection Name=&amp;quot;Hello World Collection&amp;quot; …&amp;gt;&lt;br /&gt;
&amp;lt;FacetCategories&amp;gt; 
&lt;br /&gt;
&amp;lt;FacetCategory Name=&amp;quot;Hello World Facet Category One&amp;quot; Type=&amp;quot;String&amp;quot;/&amp;gt; 
&lt;br /&gt;
&amp;lt;/FacetCategories&amp;gt; 
&lt;br /&gt;
&amp;lt;Items ImgBase=&amp;quot;helloworld.dzc&amp;quot;&amp;gt; 
&lt;br /&gt;
&amp;lt;Item Img=&amp;quot;#0&amp;quot; Id=&amp;quot;0&amp;quot; Href=&amp;quot;http://www.getpivot.com&amp;quot;
Name=&amp;quot;Hello World!&amp;quot;&amp;gt; 
&lt;br /&gt;
&amp;lt;Description&amp;gt; This is the only item in the collection.&amp;lt;/Description&amp;gt; 
&lt;br /&gt;
&amp;lt;Facets&amp;gt; 
&lt;br /&gt;
&amp;lt;Facet Name=&amp;quot;Hello World Facet Category One&amp;quot;&amp;gt; 
&lt;br /&gt;
&amp;lt;String Value=&amp;quot;Hello World Facet Value&amp;quot;/&amp;gt; 
&lt;br /&gt;
&amp;lt;/Facet&amp;gt; 
&lt;br /&gt;
&amp;lt;/Facets&amp;gt; 
&lt;br /&gt;
&amp;lt;/Item&amp;gt; 
&lt;br /&gt;
&amp;lt;/Items&amp;gt; 
&lt;br /&gt;
&amp;lt;/Collection&amp;gt;&lt;/pre&gt;
&lt;p&gt;
The way that I think about the Items in the Collection are in the same way that you
might think about an object.&amp;#160; For example, a Car object might have the following
properties:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Advertising blurb&lt;/li&gt;
&lt;li&gt;
Car and Driver Reviews&lt;/li&gt;
&lt;li&gt;
Color&lt;/li&gt;
&lt;li&gt;
Make&lt;/li&gt;
&lt;li&gt;
Model&lt;/li&gt;
&lt;li&gt;
Engine&lt;/li&gt;
&lt;li&gt;
0-60mph time&lt;/li&gt;
&lt;li&gt;
Max Speed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
The common values like the Color, Make, Model, 0-60mph time and max speed become the
facets or attributes that describe your object in relation to other instances of objects.&amp;#160;
Things like the advertising blurbs and car and driver reviews or descriptions belong
instead as properties of your Item directly in the Description element.
&lt;/p&gt;
&lt;p&gt;
For our data, namely ASP.NET exceptions, we’re going to define an exception as the
following:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Item&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;
Name = Exception Type&lt;/li&gt;
&lt;li&gt;
Description = Exception Message&lt;/li&gt;
&lt;li&gt;
Facets&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;
Request Path&lt;/li&gt;
&lt;li&gt;
Stack Trace&lt;/li&gt;
&lt;li&gt;
Event Time&lt;/li&gt;
&lt;li&gt;
Top Method of Stack Trace&lt;/li&gt;
&lt;li&gt;
Top My Code Method of Stack Trace&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;p&gt;
This should allow us to group and drill through the common properties that might link
exceptions together and still provide detailed error information when necessary.
&lt;/p&gt;
&lt;h3&gt;Find an API and code it
&lt;/h3&gt;
&lt;p&gt;
The second step here is to find some code/API/tool that we can enhance for our purposes.&amp;#160;
There are some great tools published by the Live Labs team – for example:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://www.getpivot.com/developer-info/download-cmd-tools.aspx"&gt;Pivot Collection
Tool for the Command Line&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.getpivot.com/developer-info/download-excel-tools.aspx"&gt;Pivot Collection
Tool for Microsoft Excel&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
While both tools could be used in this instance, in part 2 we found that some of our
Event Logs we were parsing contained more than 10,000 items and I wanted a bit more
control over how I converted the data.&amp;#160; “No touching” is the phrase of the day.&amp;#160; &lt;a href="http://pauthor.codeplex.com/"&gt;Fortunately,
the command line tool was published on CodePlex with an API we can use&lt;/a&gt;.&amp;#160;
Once you download the product you see that it contains 3 assemblies:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb.png" width="468" height="121" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
The last item there is the PauthorLib.dll which encapsulates many of the extension
points within this great tool.&amp;#160; In-fact, it exposes about 7 different namespaces
for our purposes:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_4.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb_1.png" width="301" height="148" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
For our purposes, we are going to focus on the Streaming set of namespaces.&amp;#160;
Why?&amp;#160; Well, this is namely because we are going to be dealing with a lot of data
and I didn’t want to load everything into memory before writing it to disk.&amp;#160;
If you look at the contents of the Streaming namespace, you’ll see a great class called
“AbstractCollectionSource”.&amp;#160; This looks fairly promising because it exposes two
main methods:
&lt;/p&gt;
&lt;pre class="c#" name="code"&gt;class EventLogExceptionCollectionSource : AbstractCollectionSource&lt;br /&gt;
{&lt;br /&gt;
protected override void LoadHeaderData()&lt;br /&gt;
{&lt;br /&gt;
throw new NotImplementedException();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
protected override IEnumerable&amp;lt;PivotItem&amp;gt; LoadItems()&lt;br /&gt;
{&lt;br /&gt;
throw new NotImplementedException();&lt;br /&gt;
}&lt;br /&gt;
}&lt;/pre&gt;
&lt;p&gt;
Before we do anything, though, we need a constructor.&amp;#160; The constructor will be
responsible for taking a string representing the path to our data and passing it to
our base class’s constructor.
&lt;/p&gt;
&lt;pre class="c#" name="code"&gt;public EventLogExceptionCollectionSource(string filePath)&lt;br /&gt;
: base(filePath)&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
// Do nothing else.&lt;br /&gt;
&lt;br /&gt;
}&lt;/pre&gt;
Then, the first method, LoadHeaderData, is where we define our facets – Request Path,
Stack Trace, etc.&amp;#160; - as well as the data types that each facet will be.&amp;#160;
So, our code will be fairly simple and straight-forward: &lt;pre class="c#" name="code"&gt;protected override void LoadHeaderData()&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
this.CachedCollectionData.FacetCategories.Add(&lt;br /&gt;
new PivotFacetCategory(STACKTRACE, 
&lt;br /&gt;
PivotFacetType.LongString));&lt;br /&gt;
this.CachedCollectionData.FacetCategories.Add(&lt;br /&gt;
new PivotFacetCategory(REQUESTPATH, 
&lt;br /&gt;
PivotFacetType.String));&lt;br /&gt;
this.CachedCollectionData.FacetCategories.Add(&lt;br /&gt;
new PivotFacetCategory(EVENTTIME, 
&lt;br /&gt;
PivotFacetType.DateTime));&lt;br /&gt;
this.CachedCollectionData.FacetCategories.Add(&lt;br /&gt;
new PivotFacetCategory(TOPMETHOD, 
&lt;br /&gt;
PivotFacetType.String));&lt;br /&gt;
this.CachedCollectionData.FacetCategories.Add(&lt;br /&gt;
new PivotFacetCategory(TOPAPPMETHOD, 
&lt;br /&gt;
PivotFacetType.String));&lt;br /&gt;
&lt;br /&gt;
this.CachedCollectionData.Name = &amp;quot;Event Log Error Messages&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}&lt;/pre&gt;
&lt;p&gt;
The second method, LoadItems(), is responsible for doing exactly what it suggests
– this is where we load the data from whichever source we care about and then convert
it into our PivotItem collection.&amp;#160; For our purposes, we’re going to load the
XML file we defined in &lt;a href="http://www.samuraiprogrammer.com/blog/2010/08/29/ParsingASPNETEventLogErrorMessagesForFunAndProfit.aspx"&gt;Part
1&lt;/a&gt; of this series into a list of EventLogMessage objects and then convert those
EventLogMessage objects into PivotItem objects:
&lt;/p&gt;
&lt;pre class="c#" name="code"&gt;protected override IEnumerable&amp;lt;PivotItem&amp;gt; LoadItems()&lt;br /&gt;
{&lt;br /&gt;
// Load XML file&lt;br /&gt;
XDocument document = XDocument.Load(this.BasePath);&lt;br /&gt;
&lt;br /&gt;
// Populate collection of EventLogMessage objects&lt;br /&gt;
var messages = from message in document.Descendants(&amp;quot;Message&amp;quot;)&lt;br /&gt;
select EventLogMessage.Load(message.Value);&lt;br /&gt;
&lt;br /&gt;
int index = 0;&lt;br /&gt;
foreach (EventLogMessage message in messages)&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
PivotItem item = new PivotItem(index.ToString(), this);&lt;br /&gt;
item.Name = message.Exceptiontype;&lt;br /&gt;
item.Description = message.Exceptionmessage;&lt;br /&gt;
item.AddFacetValues(REQUESTPATH, message.Requestpath);&lt;br /&gt;
item.AddFacetValues(STACKTRACE, message.Stacktrace);&lt;br /&gt;
item.AddFacetValues(EVENTTIME, message.Eventtime);&lt;br /&gt;
item.AddFacetValues(TOPMETHOD, message.StackTraceFrames[0].Method);&lt;br /&gt;
item.AddFacetValues(TOPAPPMETHOD, GetFirstNonMicrosoftMethod(message.StackTraceFrames));&lt;br /&gt;
&lt;br /&gt;
index++;&lt;br /&gt;
yield return item;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
}&lt;/pre&gt;
&lt;p&gt;
The key method calls from above are the AddFacetValues(…) method calls.&amp;#160; This
method essentially sets the attributes we wish to have our data pivot upon.&amp;#160;
This, by itself, isn’t enough to generate our great pivot calls – we need to call
our code from somewhere.&amp;#160; Since this is a simple app, we’re going to make it
a console app.&amp;#160; For our Collection to get generated we need to use a few other
objects included in this API:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EventLogExceptionCollectionSource&lt;/strong&gt; – The class we created above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HtmlImageCreationSourceFilter&lt;/strong&gt; – This class will generate the tile
in the Pivot based upon some HTML template we specify.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LocalCxmlCollectionTarget&lt;/strong&gt; – Generates the Collection XML file at
the path we specify.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DeepZoomTargetFilter&lt;/strong&gt; – Generates the deep zoom files to support our
collection XML file and also enables all of our fancy transitions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
In practice, the code is pretty simple and straight forward and I applaud the people
who wrote this library:
&lt;/p&gt;
&lt;pre class="c#" name="code"&gt;private static void GenerateExceptionPivot(string inputFile, string outputFolder)&lt;br /&gt;
{&lt;br /&gt;
string collectionName = Path.Combine(outputFolder, &amp;quot;MyExceptions.cxml&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
EventLogExceptionCollectionSource source = 
&lt;br /&gt;
new EventLogExceptionCollectionSource(inputFile);&lt;br /&gt;
HtmlImageCreationSourceFilter sourceFilter1 = 
&lt;br /&gt;
new HtmlImageCreationSourceFilter(source);&lt;br /&gt;
sourceFilter1.HtmlTemplate = 
&lt;br /&gt;
&amp;quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;{name}&amp;lt;/h1&amp;gt;{description}&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
sourceFilter1.Width = 600;&lt;br /&gt;
sourceFilter1.Height = 600;&lt;br /&gt;
&lt;br /&gt;
LocalCxmlCollectionTarget target = 
&lt;br /&gt;
new LocalCxmlCollectionTarget(collectionName);&lt;br /&gt;
DeepZoomTargetFilter targetFilter1 = 
&lt;br /&gt;
new DeepZoomTargetFilter(target);&lt;br /&gt;
targetFilter1.Write(sourceFilter1);&lt;br /&gt;
&lt;br /&gt;
}&lt;/pre&gt;
&lt;p&gt;
That last statement, targetFilter1.Write(…) is what will actually execute everything
and write our resultant files to disk.
&lt;/p&gt;
&lt;h3&gt;Generate and Test the collection
&lt;/h3&gt;
&lt;p&gt;
So, now if we run our console application and call that GenerateExceptionPivot(…)
method, we’ll get some great output.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_6.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb_2.png" width="644" height="361" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
What’s nice about the Library is that it provides progress as it iterates through
your data (in the red rectangle) and also in the blue rectangle, we need that it’s
multi-threaded by default.&amp;#160; This is primarily for the most intensive part of
the operation – the creation of the deep zoom artifacts.&amp;#160; If you have one of
those new fangled machines with 2+ cores, you can tweak the number of threads that
it will spawn for this operation by setting the ThreadCount property of the DeepZoomTargetFilter
object.&amp;#160; This may or may not improve your performance but it’s nice that the
option is available.
&lt;/p&gt;
&lt;pre class="c#" name="code"&gt;...&lt;br /&gt;
DeepZoomTargetFilter targetFilter1 = 
&lt;br /&gt;
new DeepZoomTargetFilter(target);&lt;br /&gt;
&lt;br /&gt;
&lt;font color="#ff0000"&gt;&lt;strong&gt;targetFilter1.ThreadCount = 100;&lt;br /&gt;
&lt;/strong&gt;&lt;/font&gt;targetFilter1.Write(sourceFilter1);&lt;br /&gt;
...&lt;/pre&gt;
&lt;p&gt;
Once our collection has been generated, we can browse it in an explorer.exe window
just to get an idea of what our code has wrought:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_10.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb_4.png" width="640" height="218" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
And then to test it, you can just point the Live Labs Pivot application at our “MyExceptions.cxml”
file and view the wonderful data.&amp;#160; For example, you can look at the Event Time
in the histogram view to see how your exceptions broke down over time.&amp;#160; You can
also filter your data by things like the RequestPath (the page that threw the exception)
or the Method that was at the top of the callstack.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_12.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb_5.png" width="626" height="484" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Then, you can zoom in on a specific time slice you care about:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_14.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb_6.png" width="544" height="484" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Then, if you want to view the details for a specific instance, just click the corresponding
tile.&amp;#160; Then, a new side bar will appear on the right hand side with all of the
details we stored in this record:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_16.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/Windows-Live-Writer/01d5145cc9d9_135BB/image_thumb_7.png" width="281" height="429" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
We generated a single collection in this blog post.&amp;#160; One thing to keep in mind
is that each collection should have no more than 3,000 items.&amp;#160; For collections
in which you want to have more than 3,000 items, you should look at potentially creating
a Linked Collection.&amp;#160; That will be the subject of an upcoming blog post.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
Until next time!
&lt;/p&gt;</description>
      <comments>http://www.samuraiprogrammer.com/blog/CommentView,guid,a7f8712d-020c-4cd3-acf3-8342ddc1e629.aspx</comments>
      <category>ASP.NET</category>
      <category>Development</category>
      <category>Pivot</category>
    </item>
    <item>
      <trackback:ping>http://www.samuraiprogrammer.com/blog/Trackback.aspx?guid=a06708f7-9f9b-4ea2-8844-b13dad549af5</trackback:ping>
      <pingback:server>http://www.samuraiprogrammer.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.samuraiprogrammer.com/blog/PermaLink,guid,a06708f7-9f9b-4ea2-8844-b13dad549af5.aspx</pingback:target>
      <dc:creator>Greg Varveris</dc:creator>
      <wfw:comment>http://www.samuraiprogrammer.com/blog/CommentView,guid,a06708f7-9f9b-4ea2-8844-b13dad549af5.aspx</wfw:comment>
      <wfw:commentRss>http://www.samuraiprogrammer.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=a06708f7-9f9b-4ea2-8844-b13dad549af5</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/content/binary/WindowsLiveWriter/ParsingASP.NETEventLogErrorMessagesforF_445/image_4.png">
            <img style="border-right-width: 0px; margin: 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" align="left" src="http://www.samuraiprogrammer.com/blog/content/binary/WindowsLiveWriter/ParsingASP.NETEventLogErrorMessagesforF_445/image_thumb_1.png" width="189" height="158" />
          </a> Sometimes
a customer will ask me to look at their site and make some recommendations on what
can be improved.  One of the many things I’ll look at is their event logs. 
One of the nice things about ASP.NET is that when you encounter an unhandled exception,
an event will be placed into your Application event log.  The message of the
event log entry will usually include lots of good stuff like the application, path,
machine name, exception type, stack trace, etc.  Loads of great stuff and all
for free.  For customers that don’t have a centralized exception logging strategy,
this can be a gold mine.
</p>
        <p>
The way it usually works is that they will provide me an EVTX from their servers. 
If you’re not aware, an EVTX is just an archive of the events from the event log you
specify.  By itself, looking at the raw event logs from a server can be quite
daunting.  There are usually thousands of entries in the event log and filtering
down to what you actually care about can be exhausting.  Even if you do find
a series of ASP.NET event log messages, the problem has always been – how do you take
all of this great information that’s just dumped into the Message property of the
event log entry and put it into a format you can easily report on, generate statistics,
etc.  Fortunately, I have a non-painful solution.  
</p>
        <p>
I’ve broken this down into a relatively simple 4-step process:
</p>
        <ul>
          <li>
Get the EVTX 
</li>
          <li>
Generate a useful XML file 
</li>
          <li>
Parse into an object model 
</li>
          <li>
Analyze and report on the data 
</li>
        </ul>
        <p>
Let’s get to it.
</p>
        <h3>Step 1:  Get the EVTX
</h3>
        <p>
This step is pretty short and sweet.  In the Event Log manager, select the “Application”
group and then select the “Save All Events As…” option.  
</p>
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/content/binary/WindowsLiveWriter/ParsingASP.NETEventLogErrorMessagesforF_445/image_2.png">
            <img style="border-right-width: 0px; margin: 10px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/WindowsLiveWriter/ParsingASP.NETEventLogErrorMessagesforF_445/image_thumb.png" width="451" height="146" />
          </a>
        </p>
        <p>
That will produce an EVTX file with whatever name you specify.  Once you have
the file, transfer it to your machine as you generally do not want to install too
many tools in your production environment.
</p>
        <h3>Step 2:  Generate a useful XML file
</h3>
        <p>
Now that we have the raw EVTX file, we can get just the data we care about using <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07&amp;displaylang=en" target="_blank">a
great tool called LogParser</a>.  <a href="http://www.codinghorror.com/blog/2005/08/microsoft-logparser.html" target="_blank">Jeff
Atwood did a nice little write-up on the tool</a> but simply put it’s <strong>the </strong>Swiss
Army knife of parsing tools.  It can do just about anything data related you
would wish using a nice pseudo-SQL language.  We’ll use the tool to pull out
just the data from the event log we want and dump it into an XML file.  The query
that we can use for this task is daunting in its simplicity:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <span style="color: #0000ff">SELECT</span> Message <span style="color: #0000ff">INTO</span> MyData.xml<br /><span style="color: #0000ff">FROM</span> ‘*.evtx’<br /><span style="color: #0000ff">WHERE</span> EventID=1309</pre>
          <br />
        </div>
        <p>
The only other thing we need to tell LogParser is the format in which it the data
is coming in and the format to put it into.  This makes our single command the
following:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">C:\&gt;logparser -i:EVT -o:XML<br />
"<span style="color: #0000ff">SELECT</span> Message <span style="color: #0000ff">INTO</span> MyData.xml <span style="color: #0000ff">FROM</span> ‘*.evtx’ <span style="color: #0000ff">WHERE</span> EventID=1309" </pre>
          <br />
        </div>
        <p>
This will produce a nice XML file that looks something like the following:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <span style="color: #0000ff">&lt;?</span>
            <span style="color: #800000">xml</span>
            <span style="color: #ff0000">version</span>
            <span style="color: #0000ff">="1.0"</span>
            <span style="color: #ff0000">encoding</span>
            <span style="color: #0000ff">="ISO-10646-UCS-2"</span>
            <span style="color: #ff0000">standalone</span>
            <span style="color: #0000ff">="yes"</span> ?<span style="color: #0000ff">&gt;</span><br /><span style="color: #0000ff">&lt;</span><span style="color: #800000">ROOT</span><span style="color: #ff0000">DATE_CREATED</span><span style="color: #0000ff">="2010-08-29
06:04:20"</span><span style="color: #ff0000">CREATED_BY</span><span style="color: #0000ff">="Microsoft
Log Parser V2.2"</span><span style="color: #0000ff">&gt;</span><br /><span style="color: #0000ff">&lt;</span><span style="color: #800000">ROW</span><span style="color: #0000ff">&gt;</span><br /><span style="color: #0000ff">&lt;</span><span style="color: #800000">Message</span><span style="color: #0000ff">&gt;</span>Event
code: 3005 Event message: An unhandled exception has occurred... 
<br /><span style="color: #0000ff">&lt;/</span><span style="color: #800000">Message</span><span style="color: #0000ff">&gt;</span><br /><span style="color: #0000ff">&lt;/</span><span style="color: #800000">ROW</span><span style="color: #0000ff">&gt;</span><br />
...<br /><span style="color: #0000ff">&lt;/</span><span style="color: #800000">ROOT</span><span style="color: #0000ff">&gt;</span></pre>
          <br />
        </div>
        <p>
One thing that you may notice is that all of the nicely formatted data from our original
event log message is munged together into one unending string.  This will actually
work in our favor but more on that in the next step.
</p>
        <h3>
        </h3>
        <h3>
        </h3>
        <h3>Step 3:  Parse into an object model
</h3>
        <p>
So, now that we have an XML file with all of our event details, let’s do some parsing. 
Since all of our data is in one string, the simplest method is to apply a RegEx expression
with grouping to grab the data we care about.  
</p>
        <blockquote>
          <p>
            <em>
              <strong>In a future post, I’ll talk about a much faster way of getting this type
of data without a RegEx expression.  </strong>
            </em>
            <a href="http://msdn.microsoft.com/en-us/magazine/cc300800.aspx" target="_blank">
              <em>
                <strong>After
all, refactoring is a way of life for developers</strong>
              </em>
            </a>
            <em>
              <strong>.</strong>
            </em>
          </p>
        </blockquote>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <span style="color: #0000ff">private</span>
            <span style="color: #0000ff">const</span>
            <span style="color: #0000ff">string</span> LargeRegexString
= <span style="color: #006080">@"Event code:(?&lt;Eventcode&gt;.+)"</span> +<br /><span style="color: #006080">@"Event message:(?&lt;Eventmessage&gt;.+)"</span> +<br /><span style="color: #006080">@"Event time:(?&lt;Eventtime&gt;.+)"</span> +<br /><span style="color: #006080">@"Event time \(UTC\):(?&lt;EventtimeUTC&gt;.+)"</span> +<br /><span style="color: #006080">@"Event ID:(?&lt;EventID&gt;.+)"</span> +<br /><span style="color: #006080">@"Event sequence:(?&lt;Eventsequence&gt;.+)"</span> +<br /><span style="color: #006080">@"Event occurrence:(?&lt;Eventoccurrence&gt;.+)"</span> +<br /><span style="color: #006080">@"Event detail code:(?&lt;Eventdetailcode&gt;.+)"</span> +<br /><span style="color: #006080">@"Application information:(?&lt;Applicationinformation&gt;.+)"</span> +<br /><span style="color: #006080">@"Application domain:(?&lt;Applicationdomain&gt;.+)"</span> +<br /><span style="color: #006080">@"Trust level:(?&lt;Trustlevel&gt;.+)"</span> +<br /><span style="color: #006080">@"Full Application Virtual Path:(?&lt;FullApplicationVirtualPath&gt;.+)"</span> +<br /><span style="color: #006080">@"Application Path:(?&lt;ApplicationPath&gt;.+)"</span> +<br /><span style="color: #006080">@"Machine name:(?&lt;Machinename&gt;.+)"</span> +<br /><span style="color: #006080">@"Process information:(?&lt;Processinformation&gt;.+)"</span> +<br /><span style="color: #006080">@"Process ID:(?&lt;ProcessID&gt;.+)"</span> +<br /><span style="color: #006080">@"Process name:(?&lt;Processname&gt;.+)"</span> +<br /><span style="color: #006080">@"Account name:(?&lt;Accountname&gt;.+)"</span> +<br /><span style="color: #006080">@"Exception information:(?&lt;Exceptioninformation&gt;.+)"</span> +<br /><span style="color: #006080">@"Exception type:(?&lt;Exceptiontype&gt;.+)"</span> +<br /><span style="color: #006080">@"Exception message:(?&lt;Exceptionmessage&gt;.+)"</span> +<br /><span style="color: #006080">@"Request information:(?&lt;Requestinformation&gt;.+)"</span> +<br /><span style="color: #006080">@"Request URL:(?&lt;RequestURL&gt;.+)"</span> +<br /><span style="color: #006080">@"Request path:(?&lt;Requestpath&gt;.+)"</span> +<br /><span style="color: #006080">@"User host address:(?&lt;Userhostaddress&gt;.+)"</span> +<br /><span style="color: #006080">@"User:(?&lt;User&gt;.+)"</span> +<br /><span style="color: #006080">@"Is authenticated:(?&lt;Isauthenticated&gt;.+)"</span> +<br /><span style="color: #006080">@"Authentication Type:(?&lt;AuthenticationType&gt;.+)"</span> +<br /><span style="color: #006080">@"Thread account name:(?&lt;Threadaccountname&gt;.+)"</span> +<br /><span style="color: #006080">@"Thread information:(?&lt;Threadinformation&gt;.+)"</span> +<br /><span style="color: #006080">@"Thread ID:(?&lt;ThreadID&gt;.+)"</span> +<br /><span style="color: #006080">@"Thread account name:(?&lt;Threadaccountname&gt;.+)"</span> +<br /><span style="color: #006080">@"Is impersonating:(?&lt;Isimpersonating&gt;.+)"</span> +<br /><span style="color: #006080">@"Stack trace:(?&lt;Stacktrace&gt;.+)"</span> +<br /><span style="color: #006080">@"Custom event details:(?&lt;Customeventdetails&gt;.+)"</span>;</pre>
          <br />
        </div>
        <p>
Now that we have our RegEx, we’ll just write the code to match it against a string
and populate our class.   While I’ve included the entire regex above, I’ve
only included a partial implementation of the class population below. 
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <span style="color: #0000ff">public</span>
            <span style="color: #0000ff">class</span> EventLogMessage<br />
{<br /><br /><span style="color: #0000ff">private</span><span style="color: #0000ff">static</span> Regex
s_regex = <span style="color: #0000ff">new</span> Regex(LargeRegexString, RegexOptions.Compiled);<br /><br /><span style="color: #0000ff">public</span><span style="color: #0000ff">static</span> EventLogMessage
Load(<span style="color: #0000ff">string</span> rawMessageText)<br />
{<br /><br />
Match myMatch = s_regex.Match(rawMessageText);<br />
EventLogMessage message = <span style="color: #0000ff">new</span> EventLogMessage();<br />
message.Eventcode = myMatch.Groups[<span style="color: #006080">"Eventcode"</span>].Value;<br />
message.Eventmessage = myMatch.Groups[<span style="color: #006080">"Eventmessage"</span>].Value;<br />
message.Eventtime = myMatch.Groups[<span style="color: #006080">"Eventtime"</span>].Value;<br />
message.EventtimeUTC = myMatch.Groups[<span style="color: #006080">"EventtimeUTC"</span>].Value;<br />
message.EventID = myMatch.Groups[<span style="color: #006080">"EventID"</span>].Value;<br />
message.Eventsequence = myMatch.Groups[<span style="color: #006080">"Eventsequence"</span>].Value;<br />
message.Eventoccurrence = myMatch.Groups[<span style="color: #006080">"Eventoccurrence"</span>].Value;<br />
...<br /><span style="color: #0000ff">return</span> message;<br />
}<br /><br /><span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> Eventcode
{ get; set; }<br /><span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> Eventmessage
{ get; set; }<br /><span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> Eventtime
{ get; set; }<br /><span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> EventtimeUTC
{ get; set; }<br /><span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> EventID
{ get; set; }<br /><span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> Eventsequence
{ get; set; }<br /><span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> Eventoccurrence
{ get; set; }<br />
...<br />
}</pre>
          <br />
        </div>
        <p>
The last step is just to read in the XML file and instantiate these objects.
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">XDocument document = XDocument.Load(<span style="color: #006080">@"&lt;path
to data&gt;\MyData.xml"</span>);<br /><br />
var messages = from message <span style="color: #0000ff">in</span> document.Descendants(<span style="color: #006080">"Message"</span>)<br />
select EventLogMessage.Load(message.Value);</pre>
          <br />
        </div>
        <p>
Now that we have our objects and everything is parsed just right, we can <strong>finally </strong>get
some statistics and make sense of the data.
</p>
        <h3>Step 4:  Analyze and report on the data
</h3>
        <p>
This last step is really the whole point of this exercise.  Fortunately, now
that all of the data is an easily query’able format using our old friend LINQ, the
actual aggregates and statistics are trivial.  Really, though, everyone’s needs
are going to be different but I’ll provide a few queries that might be useful.
</p>
        <h4>Query 1:  Exception Type Summary
</h4>
        <p>
For example, let’s say you wanted to output a breakdown of the various Exception Types
in your log file.  The query you would use for that would be something like:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">var results = from log <span style="color: #0000ff">in</span> messages<br />
group log by log.Exceptiontype into l<br />
orderby l.Count() descending, l.Key<br />
select <span style="color: #0000ff">new</span><br />
{<br />
ExceptionType = l.Key,<br />
ExceptionCount = l.Count()<br />
};<br /><br /><span style="color: #0000ff">foreach</span> (var result <span style="color: #0000ff">in</span> results)<br />
{<br /><br />
Console.WriteLine(<span style="color: #006080">"{0} : {1} time(s)"</span>, 
<br />
result.ExceptionType, 
<br />
result.ExceptionCount);<br /><br />
}</pre>
          <br />
        </div>
        <p>
This would then output something like:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">WebException : 15 time(s)<br />
InvalidOperationException : 7 time(s)<br />
NotImplementedException : 2 time(s)<br />
InvalidCastException : 1 time(s)<br />
MissingMethodException : 1 time(s)</pre>
          <br />
        </div>
        <h4>Query 2:  Exception Type and Request URL Summary
</h4>
        <p>
Let’s say that you wanted to go deeper and get the breakdown of which URL’s generated
the most exceptions.  You can just expand that second foreach loop in the above
snippet to do the following:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <span style="color: #0000ff">foreach</span> (var
result <span style="color: #0000ff">in</span> results)<br />
{<br /><br />
Console.WriteLine(<span style="color: #006080">"{0} : {1} time(s)"</span>, 
<br />
result.ExceptionType, 
<br />
result.ExceptionCount);<br /><br />
var requestUrls = from urls <span style="color: #0000ff">in</span> messages<br /><span style="color: #0000ff">where</span> urls.Exceptiontype == result.ExceptionType<br />
group urls by urls.RequestURL.ToLower() into url<br />
orderby url.Count() descending, url.Key<br />
select <span style="color: #0000ff">new</span><br />
{<br />
RequestUrl = url.Key,<br />
Count = url.Count()<br />
};<br /><br /><span style="color: #0000ff">foreach</span> (var url <span style="color: #0000ff">in</span> requestUrls){<br /><br />
Console.WriteLine(<span style="color: #006080">"\t{0} : {1} times "</span>,<br />
url.RequestUrl,<br />
url.Count);<br />
} 
<br />
}</pre>
          <br />
        </div>
        <p>
This then would produce output like this:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">WebException  : 15 time(s)<br />
http://localhost/menusample/default<span style="color: #ff0000">.</span>aspx : 11
times<br />
http://localhost:63188/menusample/default<span style="color: #ff0000">.</span>aspx
: 4 times<br />
InvalidOperationException : 7 time(s)<br />
http://localhost:63188/menusample/default<span style="color: #ff0000">.</span>aspx
: 6 times<br />
http://localhost/menusample/default<span style="color: #ff0000">.</span>aspx : 1 times<br />
NotImplementedException : 2 time(s)<br />
http://localhost/samplewebsiteerror/default<span style="color: #ff0000">.</span>aspx
: 2 times<br />
InvalidCastException : 1 time(s)<br />
http://localhost:63188/menusample/default<span style="color: #ff0000">.</span>aspx
: 1 times<br />
MissingMethodException : 1 time(s)<br />
http://localhost:63188/menusample/default<span style="color: #ff0000">.</span>aspx
: 1 times</pre>
          <br />
        </div>
        <h4>Query 3:  Exception Type, Request URL and Method Name Summary
</h4>
        <p>
You can even go deeper, if you so desire, to find out which of your methods threw
the most exceptions.  For this to work, we need to make a slight change to our
EventLogMessage class to parse the Stack Trace data into a class.  First, we’ll
start with our simple little StackTraceFrame class:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <span style="color: #0000ff">public</span>
            <span style="color: #0000ff">class</span> StackTraceFrame<br />
{<br /><span style="color: #0000ff">public</span><span style="color: #0000ff">string</span> Method
{ get; set; }<br /><br />
}</pre>
          <br />
        </div>
        <p>
Second, add a new property to our EventLogMessage class to hold a List&lt;StackTraceFrame&gt;:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <span style="color: #0000ff">public</span> List&lt;StackTraceFrame&gt;
StackTraceFrames { get; set; }</pre>
          <br />
        </div>
        <p>
Lastly, add a method (and its caller) to parse out the stack frames and assign the
resulting List to the StackTraceFrames property mentioned above:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <span style="color: #0000ff">public</span> EventLogMessage(<span style="color: #0000ff">string</span> rawMessageText)<br />
{<br />
Match myMatch = s_regex.Match(rawMessageText);<br />
...<br />
Stacktrace = myMatch.Groups[<span style="color: #006080">"Stacktrace"</span>].Value;<br />
...<br />
StackTraceFrames = ParseStackTrace(Stacktrace);<br />
}<br /><br /><span style="color: #0000ff">private</span> List&lt;StackTraceFrame&gt; ParseStackTrace(<span style="color: #0000ff">string</span> stackTrace)<br />
{<br />
List&lt;StackTraceFrame&gt; frames = <span style="color: #0000ff">new</span> List&lt;StackTraceFrame&gt;();<br /><span style="color: #0000ff">string</span>[] stackTraceSplit = stackTrace.Split(<span style="color: #0000ff">new</span><span style="color: #0000ff">string</span>[]
{ <span style="color: #006080">" at "</span> }, 
<br />
StringSplitOptions.RemoveEmptyEntries);<br /><span style="color: #0000ff">foreach</span> (<span style="color: #0000ff">string</span> st <span style="color: #0000ff">in</span> stackTraceSplit)<br />
{<br /><span style="color: #0000ff">if</span> (!<span style="color: #0000ff">string</span>.IsNullOrEmpty(st))<br />
{<br />
frames.Add(<span style="color: #0000ff">new</span> StackTraceFrame() { Method = st
});<br />
}<br />
}<br /><span style="color: #0000ff">return</span> frames;<br />
}</pre>
          <br />
        </div>
        <blockquote>
          <p>
            <em>
              <strong>Please Note:  You could enhance the ParseStackTrace(…) method to
parse out the source files, line numbers, etc. I’ll leave this as an exercise for
you, dear reader.</strong>
            </em>
          </p>
        </blockquote>
        <p>
Now that we have the infrastructure in place, the query is just as simple.  We’ll
just nest this additional query inside of our URL query like so:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <span style="color: #0000ff">foreach</span> (var
url <span style="color: #0000ff">in</span> requestUrls){<br /><br />
Console.WriteLine(<span style="color: #006080">"\t{0} : {1} times "</span>,<br />
url.RequestUrl,<br />
url.Count);<br /><br />
var methods = from method <span style="color: #0000ff">in</span> messages<br /><span style="color: #0000ff">where</span><span style="color: #0000ff">string</span>.Equals(method.RequestURL, 
<br />
url.RequestUrl, 
<br />
StringComparison.InvariantCultureIgnoreCase) 
<br />
&amp;&amp;<br /><span style="color: #0000ff">string</span>.Equals(method.Exceptiontype, 
<br />
result.ExceptionType, 
<br />
StringComparison.InvariantCultureIgnoreCase)<br />
group method by method.StackTraceFrames[0].Method into mt<br />
orderby mt.Count() descending, mt.Key<br />
select <span style="color: #0000ff">new</span><br />
{<br />
MethodName = mt.Key,<br />
Count = mt.Count()<br />
};<br /><br /><span style="color: #0000ff">foreach</span> (var method <span style="color: #0000ff">in</span> methods)<br />
{<br />
Console.WriteLine(<span style="color: #006080">"\t\t{0} : {1} times "</span>,<br />
method.MethodName,<br />
method.Count<br />
);<br />
}<br />
} </pre>
          <br />
        </div>
        <p>
This would then produce output like the following:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">WebException  : 15 time(s)<br />
http://localhost/menusample/default.aspx : 11 times<br />
System.Net.HttpWebRequest.GetResponse() : 11 times<br />
http://localhost:63188/menusample/default.aspx : 4 times<br />
System.Net.HttpWebRequest.GetResponse() : 4 times<br />
InvalidOperationException : 7 time(s)<br />
http://localhost:63188/menusample/default.aspx : 6 times<br />
System.Web.UI.WebControls.Menu... : 6 times<br />
http://localhost/menusample/default.aspx : 1 times<br />
System.Web.UI.WebControls.Menu... : 1 times</pre>
          <br />
        </div>
        <p>
One last thing you may notice is that the in the example above, the first frame for
each of those exceptions are somewhere in the bowels of the .NET BCL.  You may
want to filter this out even further to only return <strong>YOUR </strong>method. 
This can be accomplished very easily with the method below.  It will simply loop
through the StackTraceFrame List and return the first method it encounters that does
not start with “System.” or “Microsoft.”.
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <span style="color: #0000ff">private</span>
            <span style="color: #0000ff">static</span>
            <span style="color: #0000ff">string</span> GetMyMethod(List&lt;StackTraceFrame&gt;
frames)<br />
{<br /><br /><span style="color: #0000ff">foreach</span> (StackTraceFrame frame <span style="color: #0000ff">in</span> frames)<br />
{<br /><br /><span style="color: #0000ff">if</span> (!frame.Method.StartsWith(<span style="color: #006080">"System."</span>)
&amp;&amp;<br />
!frame.Method.StartsWith(<span style="color: #006080">"Microsoft."</span>))<br /><span style="color: #0000ff">return</span> frame.Method;<br /><br /><br />
}<br /><br /><span style="color: #0000ff">return</span><span style="color: #006080">"No User
Code detected."</span>;<br />
}</pre>
          <br />
        </div>
        <p>
Then, you can just call that method from the new query we wrote above:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">var methods = from method <span style="color: #0000ff">in</span> messages<br /><span style="color: #0000ff">where</span> ...<br />
group method by 
<br />
GetMyMethod(method.StackTraceFrames) into mt<br />
...</pre>
          <br />
        </div>
        <p>
Finally, with this new snippet in place, we’ll get output like this:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">WebException  : 15 time(s)<br />
http://localhost/menusample/default.aspx : 11 times<br />
_Default.Page_Load(Object sender, EventArgs e)...: 8 times<br />
No User Code detected. : 3 times<br /><br />
http://localhost:63188/menusample/default.aspx : 4 times<br />
_Default.Page_Load(Object sender, EventArgs e)... : 1 times<br />
No User Code detected. : 1 times<br />
WebControls.CustomXmlHierarchicalDataSourceView.Select()... : 2 times</pre>
          <br />
        </div>
        <p>
As you can see, the sky’s the limit.
</p>
        <p>
Enjoy!
</p>
      </body>
      <title>Parsing ASP.NET event log error messages for fun and profit</title>
      <guid isPermaLink="false">http://www.samuraiprogrammer.com/blog/PermaLink,guid,a06708f7-9f9b-4ea2-8844-b13dad549af5.aspx</guid>
      <link>http://www.samuraiprogrammer.com/blog/2010/08/29/ParsingASPNETEventLogErrorMessagesForFunAndProfit.aspx</link>
      <pubDate>Sun, 29 Aug 2010 22:10:07 GMT</pubDate>
      <description>&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/WindowsLiveWriter/ParsingASP.NETEventLogErrorMessagesforF_445/image_4.png"&gt;&lt;img style="border-right-width: 0px; margin: 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" align="left" src="http://www.samuraiprogrammer.com/blog/content/binary/WindowsLiveWriter/ParsingASP.NETEventLogErrorMessagesforF_445/image_thumb_1.png" width="189" height="158" /&gt;&lt;/a&gt; Sometimes
a customer will ask me to look at their site and make some recommendations on what
can be improved.&amp;#160; One of the many things I’ll look at is their event logs.&amp;#160;
One of the nice things about ASP.NET is that when you encounter an unhandled exception,
an event will be placed into your Application event log.&amp;#160; The message of the
event log entry will usually include lots of good stuff like the application, path,
machine name, exception type, stack trace, etc.&amp;#160; Loads of great stuff and all
for free.&amp;#160; For customers that don’t have a centralized exception logging strategy,
this can be a gold mine.
&lt;/p&gt;
&lt;p&gt;
The way it usually works is that they will provide me an EVTX from their servers.&amp;#160;
If you’re not aware, an EVTX is just an archive of the events from the event log you
specify.&amp;#160; By itself, looking at the raw event logs from a server can be quite
daunting.&amp;#160; There are usually thousands of entries in the event log and filtering
down to what you actually care about can be exhausting.&amp;#160; Even if you do find
a series of ASP.NET event log messages, the problem has always been – how do you take
all of this great information that’s just dumped into the Message property of the
event log entry and put it into a format you can easily report on, generate statistics,
etc.&amp;#160; Fortunately, I have a non-painful solution.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
I’ve broken this down into a relatively simple 4-step process:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Get the EVTX 
&lt;/li&gt;
&lt;li&gt;
Generate a useful XML file 
&lt;/li&gt;
&lt;li&gt;
Parse into an object model 
&lt;/li&gt;
&lt;li&gt;
Analyze and report on the data 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Let’s get to it.
&lt;/p&gt;
&lt;h3&gt;Step 1:&amp;#160; Get the EVTX
&lt;/h3&gt;
&lt;p&gt;
This step is pretty short and sweet.&amp;#160; In the Event Log manager, select the “Application”
group and then select the “Save All Events As…” option.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/WindowsLiveWriter/ParsingASP.NETEventLogErrorMessagesforF_445/image_2.png"&gt;&lt;img style="border-right-width: 0px; margin: 10px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.samuraiprogrammer.com/blog/content/binary/WindowsLiveWriter/ParsingASP.NETEventLogErrorMessagesforF_445/image_thumb.png" width="451" height="146" /&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
That will produce an EVTX file with whatever name you specify.&amp;#160; Once you have
the file, transfer it to your machine as you generally do not want to install too
many tools in your production environment.
&lt;/p&gt;
&lt;h3&gt;Step 2:&amp;#160; Generate a useful XML file
&lt;/h3&gt;
&lt;p&gt;
Now that we have the raw EVTX file, we can get just the data we care about using &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07&amp;amp;displaylang=en" target="_blank"&gt;a
great tool called LogParser&lt;/a&gt;.&amp;#160; &lt;a href="http://www.codinghorror.com/blog/2005/08/microsoft-logparser.html" target="_blank"&gt;Jeff
Atwood did a nice little write-up on the tool&lt;/a&gt; but simply put it’s &lt;strong&gt;the &lt;/strong&gt;Swiss
Army knife of parsing tools.&amp;#160; It can do just about anything data related you
would wish using a nice pseudo-SQL language.&amp;#160; We’ll use the tool to pull out
just the data from the event log we want and dump it into an XML file.&amp;#160; The query
that we can use for this task is daunting in its simplicity:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt; Message &lt;span style="color: #0000ff"&gt;INTO&lt;/span&gt; MyData.xml&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt; ‘*.evtx’&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt; EventID=1309&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
The only other thing we need to tell LogParser is the format in which it the data
is coming in and the format to put it into.&amp;#160; This makes our single command the
following:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;C:\&amp;gt;logparser -i:EVT -o:XML&lt;br /&gt;
&amp;quot;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt; Message &lt;span style="color: #0000ff"&gt;INTO&lt;/span&gt; MyData.xml &lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt; ‘*.evtx’ &lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt; EventID=1309&amp;quot; &lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
This will produce a nice XML file that looks something like the following:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color: #800000"&gt;xml&lt;/span&gt; &lt;span style="color: #ff0000"&gt;version&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;encoding&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;ISO-10646-UCS-2&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;standalone&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;yes&amp;quot;&lt;/span&gt; ?&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ROOT&lt;/span&gt; &lt;span style="color: #ff0000"&gt;DATE_CREATED&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;2010-08-29
06:04:20&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;CREATED_BY&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;Microsoft
Log Parser V2.2&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ROW&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Message&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;Event
code: 3005 Event message: An unhandled exception has occurred... 
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Message&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;ROW&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;ROOT&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
One thing that you may notice is that all of the nicely formatted data from our original
event log message is munged together into one unending string.&amp;#160; This will actually
work in our favor but more on that in the next step.
&lt;/p&gt;
&lt;h3&gt;
&lt;/h3&gt;
&lt;h3&gt;
&lt;/h3&gt;
&lt;h3&gt;Step 3:&amp;#160; Parse into an object model
&lt;/h3&gt;
&lt;p&gt;
So, now that we have an XML file with all of our event details, let’s do some parsing.&amp;#160;
Since all of our data is in one string, the simplest method is to apply a RegEx expression
with grouping to grab the data we care about.&amp;#160; 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;&lt;strong&gt;In a future post, I’ll talk about a much faster way of getting this type
of data without a RegEx expression.&amp;#160; &lt;/strong&gt;&lt;/em&gt;&lt;a href="http://msdn.microsoft.com/en-us/magazine/cc300800.aspx" target="_blank"&gt;&lt;em&gt;&lt;strong&gt;After
all, refactoring is a way of life for developers&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;&lt;em&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;const&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; LargeRegexString
= &lt;span style="color: #006080"&gt;@&amp;quot;Event code:(?&amp;lt;Eventcode&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Event message:(?&amp;lt;Eventmessage&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Event time:(?&amp;lt;Eventtime&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Event time \(UTC\):(?&amp;lt;EventtimeUTC&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Event ID:(?&amp;lt;EventID&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Event sequence:(?&amp;lt;Eventsequence&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Event occurrence:(?&amp;lt;Eventoccurrence&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Event detail code:(?&amp;lt;Eventdetailcode&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Application information:(?&amp;lt;Applicationinformation&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Application domain:(?&amp;lt;Applicationdomain&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Trust level:(?&amp;lt;Trustlevel&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Full Application Virtual Path:(?&amp;lt;FullApplicationVirtualPath&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Application Path:(?&amp;lt;ApplicationPath&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Machine name:(?&amp;lt;Machinename&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Process information:(?&amp;lt;Processinformation&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Process ID:(?&amp;lt;ProcessID&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Process name:(?&amp;lt;Processname&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Account name:(?&amp;lt;Accountname&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Exception information:(?&amp;lt;Exceptioninformation&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Exception type:(?&amp;lt;Exceptiontype&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Exception message:(?&amp;lt;Exceptionmessage&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Request information:(?&amp;lt;Requestinformation&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Request URL:(?&amp;lt;RequestURL&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Request path:(?&amp;lt;Requestpath&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;User host address:(?&amp;lt;Userhostaddress&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;User:(?&amp;lt;User&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Is authenticated:(?&amp;lt;Isauthenticated&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Authentication Type:(?&amp;lt;AuthenticationType&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Thread account name:(?&amp;lt;Threadaccountname&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Thread information:(?&amp;lt;Threadinformation&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Thread ID:(?&amp;lt;ThreadID&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Thread account name:(?&amp;lt;Threadaccountname&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Is impersonating:(?&amp;lt;Isimpersonating&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Stack trace:(?&amp;lt;Stacktrace&amp;gt;.+)&amp;quot;&lt;/span&gt; +&lt;br /&gt;
&lt;span style="color: #006080"&gt;@&amp;quot;Custom event details:(?&amp;lt;Customeventdetails&amp;gt;.+)&amp;quot;&lt;/span&gt;;&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
Now that we have our RegEx, we’ll just write the code to match it against a string
and populate our class.&amp;#160;&amp;#160; While I’ve included the entire regex above, I’ve
only included a partial implementation of the class population below. 
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; EventLogMessage&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Regex
s_regex = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Regex(LargeRegexString, RegexOptions.Compiled);&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; EventLogMessage
Load(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; rawMessageText)&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
Match myMatch = s_regex.Match(rawMessageText);&lt;br /&gt;
EventLogMessage message = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; EventLogMessage();&lt;br /&gt;
message.Eventcode = myMatch.Groups[&lt;span style="color: #006080"&gt;&amp;quot;Eventcode&amp;quot;&lt;/span&gt;].Value;&lt;br /&gt;
message.Eventmessage = myMatch.Groups[&lt;span style="color: #006080"&gt;&amp;quot;Eventmessage&amp;quot;&lt;/span&gt;].Value;&lt;br /&gt;
message.Eventtime = myMatch.Groups[&lt;span style="color: #006080"&gt;&amp;quot;Eventtime&amp;quot;&lt;/span&gt;].Value;&lt;br /&gt;
message.EventtimeUTC = myMatch.Groups[&lt;span style="color: #006080"&gt;&amp;quot;EventtimeUTC&amp;quot;&lt;/span&gt;].Value;&lt;br /&gt;
message.EventID = myMatch.Groups[&lt;span style="color: #006080"&gt;&amp;quot;EventID&amp;quot;&lt;/span&gt;].Value;&lt;br /&gt;
message.Eventsequence = myMatch.Groups[&lt;span style="color: #006080"&gt;&amp;quot;Eventsequence&amp;quot;&lt;/span&gt;].Value;&lt;br /&gt;
message.Eventoccurrence = myMatch.Groups[&lt;span style="color: #006080"&gt;&amp;quot;Eventoccurrence&amp;quot;&lt;/span&gt;].Value;&lt;br /&gt;
...&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;return&lt;/span&gt; message;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Eventcode
{ get; set; }&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Eventmessage
{ get; set; }&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Eventtime
{ get; set; }&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; EventtimeUTC
{ get; set; }&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; EventID
{ get; set; }&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Eventsequence
{ get; set; }&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Eventoccurrence
{ get; set; }&lt;br /&gt;
...&lt;br /&gt;
}&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
The last step is just to read in the XML file and instantiate these objects.
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;XDocument document = XDocument.Load(&lt;span style="color: #006080"&gt;@&amp;quot;&amp;lt;path
to data&amp;gt;\MyData.xml&amp;quot;&lt;/span&gt;);&lt;br /&gt;
&lt;br /&gt;
var messages = from message &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; document.Descendants(&lt;span style="color: #006080"&gt;&amp;quot;Message&amp;quot;&lt;/span&gt;)&lt;br /&gt;
select EventLogMessage.Load(message.Value);&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
Now that we have our objects and everything is parsed just right, we can &lt;strong&gt;finally &lt;/strong&gt;get
some statistics and make sense of the data.
&lt;/p&gt;
&lt;h3&gt;Step 4:&amp;#160; Analyze and report on the data
&lt;/h3&gt;
&lt;p&gt;
This last step is really the whole point of this exercise.&amp;#160; Fortunately, now
that all of the data is an easily query’able format using our old friend LINQ, the
actual aggregates and statistics are trivial.&amp;#160; Really, though, everyone’s needs
are going to be different but I’ll provide a few queries that might be useful.
&lt;/p&gt;
&lt;h4&gt;Query 1:&amp;#160; Exception Type Summary
&lt;/h4&gt;
&lt;p&gt;
For example, let’s say you wanted to output a breakdown of the various Exception Types
in your log file.&amp;#160; The query you would use for that would be something like:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;var results = from log &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; messages&lt;br /&gt;
group log by log.Exceptiontype into l&lt;br /&gt;
orderby l.Count() descending, l.Key&lt;br /&gt;
select &lt;span style="color: #0000ff"&gt;new&lt;/span&gt;
&lt;br /&gt;
{&lt;br /&gt;
ExceptionType = l.Key,&lt;br /&gt;
ExceptionCount = l.Count()&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var result &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; results)&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
Console.WriteLine(&lt;span style="color: #006080"&gt;&amp;quot;{0} : {1} time(s)&amp;quot;&lt;/span&gt;, 
&lt;br /&gt;
result.ExceptionType, 
&lt;br /&gt;
result.ExceptionCount);&lt;br /&gt;
&lt;br /&gt;
}&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
This would then output something like:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;WebException : 15 time(s)&lt;br /&gt;
InvalidOperationException : 7 time(s)&lt;br /&gt;
NotImplementedException : 2 time(s)&lt;br /&gt;
InvalidCastException : 1 time(s)&lt;br /&gt;
MissingMethodException : 1 time(s)&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;h4&gt;Query 2:&amp;#160; Exception Type and Request URL Summary
&lt;/h4&gt;
&lt;p&gt;
Let’s say that you wanted to go deeper and get the breakdown of which URL’s generated
the most exceptions.&amp;#160; You can just expand that second foreach loop in the above
snippet to do the following:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var
result &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; results)&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
Console.WriteLine(&lt;span style="color: #006080"&gt;&amp;quot;{0} : {1} time(s)&amp;quot;&lt;/span&gt;, 
&lt;br /&gt;
result.ExceptionType, 
&lt;br /&gt;
result.ExceptionCount);&lt;br /&gt;
&lt;br /&gt;
var requestUrls = from urls &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; messages&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;where&lt;/span&gt; urls.Exceptiontype == result.ExceptionType&lt;br /&gt;
group urls by urls.RequestURL.ToLower() into url&lt;br /&gt;
orderby url.Count() descending, url.Key&lt;br /&gt;
select &lt;span style="color: #0000ff"&gt;new&lt;/span&gt;
&lt;br /&gt;
{&lt;br /&gt;
RequestUrl = url.Key,&lt;br /&gt;
Count = url.Count()&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var url &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; requestUrls){&lt;br /&gt;
&lt;br /&gt;
Console.WriteLine(&lt;span style="color: #006080"&gt;&amp;quot;\t{0} : {1} times &amp;quot;&lt;/span&gt;,&lt;br /&gt;
url.RequestUrl,&lt;br /&gt;
url.Count);&lt;br /&gt;
} 
&lt;br /&gt;
}&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
This then would produce output like this:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;WebException  : 15 time(s)&lt;br /&gt;
http://localhost/menusample/default&lt;span style="color: #ff0000"&gt;.&lt;/span&gt;aspx : 11
times&lt;br /&gt;
http://localhost:63188/menusample/default&lt;span style="color: #ff0000"&gt;.&lt;/span&gt;aspx
: 4 times&lt;br /&gt;
InvalidOperationException : 7 time(s)&lt;br /&gt;
http://localhost:63188/menusample/default&lt;span style="color: #ff0000"&gt;.&lt;/span&gt;aspx
: 6 times&lt;br /&gt;
http://localhost/menusample/default&lt;span style="color: #ff0000"&gt;.&lt;/span&gt;aspx : 1 times&lt;br /&gt;
NotImplementedException : 2 time(s)&lt;br /&gt;
http://localhost/samplewebsiteerror/default&lt;span style="color: #ff0000"&gt;.&lt;/span&gt;aspx
: 2 times&lt;br /&gt;
InvalidCastException : 1 time(s)&lt;br /&gt;
http://localhost:63188/menusample/default&lt;span style="color: #ff0000"&gt;.&lt;/span&gt;aspx
: 1 times&lt;br /&gt;
MissingMethodException : 1 time(s)&lt;br /&gt;
http://localhost:63188/menusample/default&lt;span style="color: #ff0000"&gt;.&lt;/span&gt;aspx
: 1 times&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;h4&gt;Query 3:&amp;#160; Exception Type, Request URL and Method Name Summary
&lt;/h4&gt;
&lt;p&gt;
You can even go deeper, if you so desire, to find out which of your methods threw
the most exceptions.&amp;#160; For this to work, we need to make a slight change to our
EventLogMessage class to parse the Stack Trace data into a class.&amp;#160; First, we’ll
start with our simple little StackTraceFrame class:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; StackTraceFrame&lt;br /&gt;
{&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Method
{ get; set; }&lt;br /&gt;
&lt;br /&gt;
}&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
Second, add a new property to our EventLogMessage class to hold a List&amp;lt;StackTraceFrame&amp;gt;:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; List&amp;lt;StackTraceFrame&amp;gt;
StackTraceFrames { get; set; }&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
Lastly, add a method (and its caller) to parse out the stack frames and assign the
resulting List to the StackTraceFrames property mentioned above:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; EventLogMessage(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; rawMessageText)&lt;br /&gt;
{&lt;br /&gt;
Match myMatch = s_regex.Match(rawMessageText);&lt;br /&gt;
...&lt;br /&gt;
Stacktrace = myMatch.Groups[&lt;span style="color: #006080"&gt;&amp;quot;Stacktrace&amp;quot;&lt;/span&gt;].Value;&lt;br /&gt;
...&lt;br /&gt;
StackTraceFrames = ParseStackTrace(Stacktrace);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; List&amp;lt;StackTraceFrame&amp;gt; ParseStackTrace(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; stackTrace)&lt;br /&gt;
{&lt;br /&gt;
List&amp;lt;StackTraceFrame&amp;gt; frames = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;StackTraceFrame&amp;gt;();&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[] stackTraceSplit = stackTrace.Split(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[]
{ &lt;span style="color: #006080"&gt;&amp;quot; at &amp;quot;&lt;/span&gt; }, 
&lt;br /&gt;
StringSplitOptions.RemoveEmptyEntries);&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; st &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; stackTraceSplit)&lt;br /&gt;
{&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.IsNullOrEmpty(st))&lt;br /&gt;
{&lt;br /&gt;
frames.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; StackTraceFrame() { Method = st
});&lt;br /&gt;
}&lt;br /&gt;
}&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;return&lt;/span&gt; frames;&lt;br /&gt;
}&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;&lt;strong&gt;Please Note:&amp;#160; You could enhance the ParseStackTrace(…) method to
parse out the source files, line numbers, etc. I’ll leave this as an exercise for
you, dear reader.&lt;/strong&gt;&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Now that we have the infrastructure in place, the query is just as simple.&amp;#160; We’ll
just nest this additional query inside of our URL query like so:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var
url &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; requestUrls){&lt;br /&gt;
&lt;br /&gt;
Console.WriteLine(&lt;span style="color: #006080"&gt;&amp;quot;\t{0} : {1} times &amp;quot;&lt;/span&gt;,&lt;br /&gt;
url.RequestUrl,&lt;br /&gt;
url.Count);&lt;br /&gt;
&lt;br /&gt;
var methods = from method &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; messages&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;where&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.Equals(method.RequestURL, 
&lt;br /&gt;
url.RequestUrl, 
&lt;br /&gt;
StringComparison.InvariantCultureIgnoreCase) 
&lt;br /&gt;
&amp;amp;&amp;amp;&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.Equals(method.Exceptiontype, 
&lt;br /&gt;
result.ExceptionType, 
&lt;br /&gt;
StringComparison.InvariantCultureIgnoreCase)&lt;br /&gt;
group method by method.StackTraceFrames[0].Method into mt&lt;br /&gt;
orderby mt.Count() descending, mt.Key&lt;br /&gt;
select &lt;span style="color: #0000ff"&gt;new&lt;/span&gt;
&lt;br /&gt;
{&lt;br /&gt;
MethodName = mt.Key,&lt;br /&gt;
Count = mt.Count()&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var method &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; methods)&lt;br /&gt;
{&lt;br /&gt;
Console.WriteLine(&lt;span style="color: #006080"&gt;&amp;quot;\t\t{0} : {1} times &amp;quot;&lt;/span&gt;,&lt;br /&gt;
method.MethodName,&lt;br /&gt;
method.Count&lt;br /&gt;
);&lt;br /&gt;
}&lt;br /&gt;
} &lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
This would then produce output like the following:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;WebException  : 15 time(s)&lt;br /&gt;
http://localhost/menusample/default.aspx : 11 times&lt;br /&gt;
System.Net.HttpWebRequest.GetResponse() : 11 times&lt;br /&gt;
http://localhost:63188/menusample/default.aspx : 4 times&lt;br /&gt;
System.Net.HttpWebRequest.GetResponse() : 4 times&lt;br /&gt;
InvalidOperationException : 7 time(s)&lt;br /&gt;
http://localhost:63188/menusample/default.aspx : 6 times&lt;br /&gt;
System.Web.UI.WebControls.Menu... : 6 times&lt;br /&gt;
http://localhost/menusample/default.aspx : 1 times&lt;br /&gt;
System.Web.UI.WebControls.Menu... : 1 times&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
One last thing you may notice is that the in the example above, the first frame for
each of those exceptions are somewhere in the bowels of the .NET BCL.&amp;#160; You may
want to filter this out even further to only return &lt;strong&gt;YOUR &lt;/strong&gt;method.&amp;#160;
This can be accomplished very easily with the method below.&amp;#160; It will simply loop
through the StackTraceFrame List and return the first method it encounters that does
not start with “System.” or “Microsoft.”.
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; GetMyMethod(List&amp;lt;StackTraceFrame&amp;gt;
frames)&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (StackTraceFrame frame &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; frames)&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!frame.Method.StartsWith(&lt;span style="color: #006080"&gt;&amp;quot;System.&amp;quot;&lt;/span&gt;)
&amp;amp;&amp;amp;&lt;br /&gt;
!frame.Method.StartsWith(&lt;span style="color: #006080"&gt;&amp;quot;Microsoft.&amp;quot;&lt;/span&gt;))&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;return&lt;/span&gt; frame.Method;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #006080"&gt;&amp;quot;No User
Code detected.&amp;quot;&lt;/span&gt;;&lt;br /&gt;
}&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
Then, you can just call that method from the new query we wrote above:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;var methods = from method &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; messages&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;where&lt;/span&gt; ...&lt;br /&gt;
group method by 
&lt;br /&gt;
GetMyMethod(method.StackTraceFrames) into mt&lt;br /&gt;
...&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
Finally, with this new snippet in place, we’ll get output like this:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;WebException  : 15 time(s)&lt;br /&gt;
http://localhost/menusample/default.aspx : 11 times&lt;br /&gt;
_Default.Page_Load(Object sender, EventArgs e)...: 8 times&lt;br /&gt;
No User Code detected. : 3 times&lt;br /&gt;
&lt;br /&gt;
http://localhost:63188/menusample/default.aspx : 4 times&lt;br /&gt;
_Default.Page_Load(Object sender, EventArgs e)... : 1 times&lt;br /&gt;
No User Code detected. : 1 times&lt;br /&gt;
WebControls.CustomXmlHierarchicalDataSourceView.Select()... : 2 times&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
As you can see, the sky’s the limit.
&lt;/p&gt;
&lt;p&gt;
Enjoy!
&lt;/p&gt;</description>
      <comments>http://www.samuraiprogrammer.com/blog/CommentView,guid,a06708f7-9f9b-4ea2-8844-b13dad549af5.aspx</comments>
      <category>ASP.NET</category>
      <category>Best Practice</category>
      <category>Development</category>
    </item>
    <item>
      <trackback:ping>http://www.samuraiprogrammer.com/blog/Trackback.aspx?guid=9d87b777-0aac-438c-9b47-91e479fea03a</trackback:ping>
      <pingback:server>http://www.samuraiprogrammer.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.samuraiprogrammer.com/blog/PermaLink,guid,9d87b777-0aac-438c-9b47-91e479fea03a.aspx</pingback:target>
      <dc:creator>Greg Varveris</dc:creator>
      <wfw:comment>http://www.samuraiprogrammer.com/blog/CommentView,guid,9d87b777-0aac-438c-9b47-91e479fea03a.aspx</wfw:comment>
      <wfw:commentRss>http://www.samuraiprogrammer.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=9d87b777-0aac-438c-9b47-91e479fea03a</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/content/binary/WindowsLiveWriter/Microoptimizationorjustgoodcodingpractic_DBB8/cheetah_2.jpg">
            <img style="border-right-width: 0px; margin: 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="cheetah" border="0" alt="cheetah" align="left" src="http://www.samuraiprogrammer.com/blog/content/binary/WindowsLiveWriter/Microoptimizationorjustgoodcodingpractic_DBB8/cheetah_thumb.jpg" width="244" height="184" />
          </a> This
is a common topic and I thought I’d write up some thoughts I have on it.  In-fact,
I was just working with a customer on improving their code reviews and what they should
be checking for and the question arose - “Should performance be targeted during a
code review?”  It’s an interesting question.  I’m a big fan of performance
testing early and often and not waiting until the end of a dev cycle but code reviews,
IMO, should focus on logic, maintainability and best practices.  I may be in
the minority and if you look around the web, you’ll see varying opinions on the topic.  <a href="http://msdn.microsoft.com/en-us/library/ff647802.aspx" target="_blank">For
example, one of the PAG articles states</a>:
</p>
        <blockquote>
          <p>
“Code reviews should be a regular part of your development process. Performance and
scalability code reviews focus on identifying coding techniques and design choices
that could lead to performance and scalability issues. The review goal is to identify
potential performance and scalability issues before the code is deployed. The cost
and effort of fixing performance and scalability flaws at development time is far
less than fixing them later in the product deployment cycle.
</p>
          <p>
Avoid performance code reviews too early in the coding phase because this can restrict
your design options. Also, bear in mind that that performance decisions often involve
tradeoffs. For example, it is easy to reduce maintainability and flexibility while
striving to optimize code.”
</p>
        </blockquote>
        <p>
As I mentioned above, I am a huge proponent of performance analysis and optimization
many times throughout a typical product development cycle.  I can say with a
fair amount of certainty that if you don’t build performance reviews into your project
plan at regular intervals, you will hit some problem (or multiple problems) in production
and have to refactor some code.  
</p>
        <p>
Circling back to the original question, though, are code reviews the place for performance
analysis?  Typically, I’d recommend using them to squash little bits of bad code
but maintainability and code-cleanliness should be first and foremost in your minds. 
That said, if you see a pattern that <strong>you know </strong>can be improved, by
all means bring it up.  What’s an example of that type of situation?  
</p>
        <p>
Let’s take a look at predicates, <a href="http://msdn.microsoft.com/en-us/library/x0b5b5bc.aspx" target="_blank">specifically
their usage in the Find method of a List&lt;T&gt;</a>.  If you’re not aware,
the Find() method performs a linear search through all of the items until it finds
the first match – then it returns.  This makes it a O(n) operation where “n”
is the number of items in the list.  Basically, this means that the more items
you have in the list, the longer a Find() operation can potentially take.  So,
if we slam about 10,000 elements into a list:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <span style="color: #0000ff">private</span>
            <span style="color: #0000ff">static</span> List&lt;Data&gt;
LoadList()<br />
{<br />
List&lt;Data&gt; myList = <span style="color: #0000ff">new</span> List&lt;Data&gt;();<br /><span style="color: #0000ff">for</span> (<span style="color: #0000ff">int</span> i
= 0; i &lt; 10000; i++)<br />
{<br />
myList.Add(<span style="color: #0000ff">new</span> Data() { Id = <span style="color: #006080">"Id"</span> +
i.ToString(), 
<br />
Value = <span style="color: #006080">"Value"</span> + i.ToString() });<br />
}<br /><br /><span style="color: #0000ff">return</span> myList;<br />
}</pre>
          <br />
        </div>
        <p>
Then, if someone wants to return the instance of the Data class that contains an Id
of say “Id10000”, they might write the following code:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <span style="color: #0000ff">static</span> Data
Find1(List&lt;Data&gt; myList, <span style="color: #0000ff">string</span> idToFind)<br />
{<br />
Data data = myList.Find(s =&gt; 
<br />
s.Id.ToLower() == 
<br />
idToFind.ToLower());<br /><br /><span style="color: #0000ff">return</span> data;<br />
}</pre>
          <br />
        </div>
        <p>
Now, keep in mind that the predicate is executed for each element in the List&lt;T&gt;
until it finds the instance you care about.  With that in mind, we would probably
want to refactor out the “idToFind.ToLower()” above the predicate since that value
isn’t changing.  So, you might end-up with something like this:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <span style="color: #0000ff">static</span> Data
Find2(List&lt;Data&gt; myList, <span style="color: #0000ff">string</span> idToFind)<br />
{<br /><br />
idToFind = idToFind.ToLower();<br /><br />
Data data = myList.Find(s =&gt; 
<br />
s.Id.ToLower() == 
<br />
idToFind);<br /><br /><span style="color: #0000ff">return</span> data;<br />
}</pre>
          <br />
        </div>
        <p>
Another route you may want to go is just to use the string.Equals(…) method to perform
the comparison.  That would look like:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <span style="color: #0000ff">static</span> Data
Find3(List&lt;Data&gt; myList, <span style="color: #0000ff">string</span> idToFind)<br />
{<br /><br />
Data data = myList.Find(s =&gt; 
<br /><span style="color: #0000ff">string</span>.Equals(<br />
s.Id, 
<br />
idToFind, 
<br />
StringComparison.<br />
InvariantCultureIgnoreCase)<br />
);<br /><br /><span style="color: #0000ff">return</span> data;<br /><br />
}</pre>
          <br />
        </div>
        <p>
Fact is, the last method <strong>IS</strong> the fastest way to perform the operation. 
I can say that without even needing to run it through a profiler.  But if you
don’t believe me…   <span style="widows: 2; text-transform: none; text-indent: 0px; border-collapse: separate; font: 14pt arial; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(0,0,0); word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"></span></p>
        <p>
          <table style="border-bottom-style: none; border-right-style: none; border-collapse: collapse; border-top-style: none; font-size: 14pt; border-left-style: none" border="0" cellspacing="0" cellpadding="0">
            <tbody>
              <tr>
                <td style="border-bottom: rgb(0,0,0) 0px solid; border-left: rgb(51,51,153) 1px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(0,0,0) 0px solid" bgcolor="#000000" height="29" width="406">
                  <div style="text-indent: 0pt">
                    <span style="font-family: calibri; color: rgb(255,255,255); font-size: 11pt">
                      <b>Function
Name</b>
                    </span>
                  </div>
                </td>
                <td style="border-bottom: rgb(0,0,0) 0px solid; border-left: rgb(0,0,0) 0px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(51,51,153) 1px solid" bgcolor="#000000" width="175">
                  <div style="text-indent: 0pt">
                    <span style="font-family: calibri; color: rgb(255,255,255); font-size: 11pt">
                      <b>Elapsed</b>
                    </span>
                  </div>
                  <div style="text-indent: 0pt">
                    <span style="font-family: calibri; color: rgb(255,255,255); font-size: 11pt">
                      <b>Inclusive
Time</b>
                    </span>
                  </div>
                </td>
              </tr>
              <tr>
                <td style="border-bottom: rgb(0,0,0) 0px solid; border-left: rgb(51,51,153) 1px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(0,0,0) 0px solid" height="14" width="406">
                  <div style="text-indent: 0pt">
                    <span style="font-family: calibri; color: rgb(0,0,0); font-size: 11pt">...Find1(System.Collections.Generic.List`1&lt;....Data&gt;,string)</span>
                  </div>
                </td>
                <td style="border-bottom: rgb(0,0,0) 0px solid; border-left: rgb(0,0,0) 0px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(51,51,153) 1px solid" width="175">
                  <div style="text-indent: 0pt" align="right">
                    <span style="font-family: calibri; color: rgb(0,0,0); font-size: 11pt">6.34</span>
                  </div>
                </td>
              </tr>
              <tr>
                <td style="border-bottom: rgb(0,0,0) 0px solid; border-left: rgb(51,51,153) 1px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(0,0,0) 0px solid" height="14" width="406">
                  <div style="text-indent: 0pt">
                    <span style="font-family: calibri; color: rgb(0,0,0); font-size: 11pt">...Find2(System.Collections.Generic.List`1&lt;....Data&gt;,string)</span>
                  </div>
                </td>
                <td style="border-bottom: rgb(0,0,0) 0px solid; border-left: rgb(0,0,0) 0px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(51,51,153) 1px solid" width="175">
                  <div style="text-indent: 0pt" align="right">
                    <span style="font-family: calibri; color: rgb(0,0,0); font-size: 11pt">4.47</span>
                  </div>
                </td>
              </tr>
              <tr>
                <td style="border-bottom: rgb(51,51,153) 1px solid; border-left: rgb(51,51,153) 1px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(0,0,0) 0px solid" height="14" width="406">
                  <div style="text-indent: 0pt">
                    <span style="font-family: calibri; color: rgb(0,0,0); font-size: 11pt">...Find3(System.Collections.Generic.List`1&lt;....Data&gt;,string)</span>
                  </div>
                </td>
                <td style="border-bottom: rgb(51,51,153) 1px solid; border-left: rgb(0,0,0) 0px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(51,51,153) 1px solid" width="175">
                  <div style="text-indent: 0pt" align="right">
                    <span style="font-family: calibri; color: rgb(0,0,0); font-size: 11pt">3.65</span>
                  </div>
                </td>
              </tr>
            </tbody>
          </table>
        </p>
        <div>That’s something I might put into the category of a micro-optimization AND just
good coding practice.  But is this something that should be caught during a code
review?  I’d say “yes” because logically it all makes sense and none of the solutions
would really hurt maintainability or readability of the code.
</div>
        <div> 
</div>
        <div>So, I’d tag this as a good coding practice.  Other thoughts on the topic?
</div>
        <div> 
</div>
        <div>Enjoy!
</div>
        <div>
        </div>
      </body>
      <title>Micro optimization or just good coding practice?</title>
      <guid isPermaLink="false">http://www.samuraiprogrammer.com/blog/PermaLink,guid,9d87b777-0aac-438c-9b47-91e479fea03a.aspx</guid>
      <link>http://www.samuraiprogrammer.com/blog/2010/08/21/MicroOptimizationOrJustGoodCodingPractice.aspx</link>
      <pubDate>Sat, 21 Aug 2010 04:36:27 GMT</pubDate>
      <description>&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/content/binary/WindowsLiveWriter/Microoptimizationorjustgoodcodingpractic_DBB8/cheetah_2.jpg"&gt;&lt;img style="border-right-width: 0px; margin: 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="cheetah" border="0" alt="cheetah" align="left" src="http://www.samuraiprogrammer.com/blog/content/binary/WindowsLiveWriter/Microoptimizationorjustgoodcodingpractic_DBB8/cheetah_thumb.jpg" width="244" height="184" /&gt;&lt;/a&gt; This
is a common topic and I thought I’d write up some thoughts I have on it.&amp;#160; In-fact,
I was just working with a customer on improving their code reviews and what they should
be checking for and the question arose - “Should performance be targeted during a
code review?”&amp;#160; It’s an interesting question.&amp;#160; I’m a big fan of performance
testing early and often and not waiting until the end of a dev cycle but code reviews,
IMO, should focus on logic, maintainability and best practices.&amp;#160; I may be in
the minority and if you look around the web, you’ll see varying opinions on the topic.&amp;#160; &lt;a href="http://msdn.microsoft.com/en-us/library/ff647802.aspx" target="_blank"&gt;For
example, one of the PAG articles states&lt;/a&gt;:
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
“Code reviews should be a regular part of your development process. Performance and
scalability code reviews focus on identifying coding techniques and design choices
that could lead to performance and scalability issues. The review goal is to identify
potential performance and scalability issues before the code is deployed. The cost
and effort of fixing performance and scalability flaws at development time is far
less than fixing them later in the product deployment cycle.
&lt;/p&gt;
&lt;p&gt;
Avoid performance code reviews too early in the coding phase because this can restrict
your design options. Also, bear in mind that that performance decisions often involve
tradeoffs. For example, it is easy to reduce maintainability and flexibility while
striving to optimize code.”
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
As I mentioned above, I am a huge proponent of performance analysis and optimization
many times throughout a typical product development cycle.&amp;#160; I can say with a
fair amount of certainty that if you don’t build performance reviews into your project
plan at regular intervals, you will hit some problem (or multiple problems) in production
and have to refactor some code.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
Circling back to the original question, though, are code reviews the place for performance
analysis?&amp;#160; Typically, I’d recommend using them to squash little bits of bad code
but maintainability and code-cleanliness should be first and foremost in your minds.&amp;#160;
That said, if you see a pattern that &lt;strong&gt;you know &lt;/strong&gt;can be improved, by
all means bring it up.&amp;#160; What’s an example of that type of situation?&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
Let’s take a look at predicates, &lt;a href="http://msdn.microsoft.com/en-us/library/x0b5b5bc.aspx" target="_blank"&gt;specifically
their usage in the Find method of a List&amp;lt;T&amp;gt;&lt;/a&gt;.&amp;#160; If you’re not aware,
the Find() method performs a linear search through all of the items until it finds
the first match – then it returns.&amp;#160; This makes it a O(n) operation where “n”
is the number of items in the list.&amp;#160; Basically, this means that the more items
you have in the list, the longer a Find() operation can potentially take.&amp;#160; So,
if we slam about 10,000 elements into a list:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; List&amp;lt;Data&amp;gt;
LoadList()&lt;br /&gt;
{&lt;br /&gt;
List&amp;lt;Data&amp;gt; myList = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;Data&amp;gt;();&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i
= 0; i &amp;lt; 10000; i++)&lt;br /&gt;
{&lt;br /&gt;
myList.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Data() { Id = &lt;span style="color: #006080"&gt;&amp;quot;Id&amp;quot;&lt;/span&gt; +
i.ToString(), 
&lt;br /&gt;
Value = &lt;span style="color: #006080"&gt;&amp;quot;Value&amp;quot;&lt;/span&gt; + i.ToString() });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;return&lt;/span&gt; myList;&lt;br /&gt;
}&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
Then, if someone wants to return the instance of the Data class that contains an Id
of say “Id10000”, they might write the following code:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Data
Find1(List&amp;lt;Data&amp;gt; myList, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; idToFind)&lt;br /&gt;
{&lt;br /&gt;
Data data = myList.Find(s =&amp;gt; 
&lt;br /&gt;
s.Id.ToLower() == 
&lt;br /&gt;
idToFind.ToLower());&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;return&lt;/span&gt; data;&lt;br /&gt;
}&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
Now, keep in mind that the predicate is executed for each element in the List&amp;lt;T&amp;gt;
until it finds the instance you care about.&amp;#160; With that in mind, we would probably
want to refactor out the “idToFind.ToLower()” above the predicate since that value
isn’t changing.&amp;#160; So, you might end-up with something like this:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Data
Find2(List&amp;lt;Data&amp;gt; myList, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; idToFind)&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
idToFind = idToFind.ToLower();&lt;br /&gt;
&lt;br /&gt;
Data data = myList.Find(s =&amp;gt; 
&lt;br /&gt;
s.Id.ToLower() == 
&lt;br /&gt;
idToFind);&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;return&lt;/span&gt; data;&lt;br /&gt;
}&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
Another route you may want to go is just to use the string.Equals(…) method to perform
the comparison.&amp;#160; That would look like:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;static&lt;/span&gt; Data
Find3(List&amp;lt;Data&amp;gt; myList, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; idToFind)&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
Data data = myList.Find(s =&amp;gt; 
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.Equals(&lt;br /&gt;
s.Id, 
&lt;br /&gt;
idToFind, 
&lt;br /&gt;
StringComparison.&lt;br /&gt;
InvariantCultureIgnoreCase)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;return&lt;/span&gt; data;&lt;br /&gt;
&lt;br /&gt;
}&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
Fact is, the last method &lt;strong&gt;IS&lt;/strong&gt; the fastest way to perform the operation.&amp;#160;
I can say that without even needing to run it through a profiler.&amp;#160; But if you
don’t believe me…&amp;#160;&amp;#160; &lt;span style="widows: 2; text-transform: none; text-indent: 0px; border-collapse: separate; font: 14pt arial; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(0,0,0); word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"&gt;&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;table style="border-bottom-style: none; border-right-style: none; border-collapse: collapse; border-top-style: none; font-size: 14pt; border-left-style: none" border="0" cellspacing="0" cellpadding="0"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="border-bottom: rgb(0,0,0) 0px solid; border-left: rgb(51,51,153) 1px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(0,0,0) 0px solid" bgcolor="#000000" height="29" width="406"&gt;
&lt;div style="text-indent: 0pt"&gt;&lt;span style="font-family: calibri; color: rgb(255,255,255); font-size: 11pt"&gt;&lt;b&gt;Function
Name&lt;/b&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style="border-bottom: rgb(0,0,0) 0px solid; border-left: rgb(0,0,0) 0px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(51,51,153) 1px solid" bgcolor="#000000" width="175"&gt;
&lt;div style="text-indent: 0pt"&gt;&lt;span style="font-family: calibri; color: rgb(255,255,255); font-size: 11pt"&gt;&lt;b&gt;Elapsed&lt;/b&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div style="text-indent: 0pt"&gt;&lt;span style="font-family: calibri; color: rgb(255,255,255); font-size: 11pt"&gt;&lt;b&gt;Inclusive
Time&lt;/b&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="border-bottom: rgb(0,0,0) 0px solid; border-left: rgb(51,51,153) 1px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(0,0,0) 0px solid" height="14" width="406"&gt;
&lt;div style="text-indent: 0pt"&gt;&lt;span style="font-family: calibri; color: rgb(0,0,0); font-size: 11pt"&gt;...Find1(System.Collections.Generic.List`1&amp;lt;....Data&amp;gt;,string)&lt;/span&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style="border-bottom: rgb(0,0,0) 0px solid; border-left: rgb(0,0,0) 0px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(51,51,153) 1px solid" width="175"&gt;
&lt;div style="text-indent: 0pt" align="right"&gt;&lt;span style="font-family: calibri; color: rgb(0,0,0); font-size: 11pt"&gt;6.34&lt;/span&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="border-bottom: rgb(0,0,0) 0px solid; border-left: rgb(51,51,153) 1px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(0,0,0) 0px solid" height="14" width="406"&gt;
&lt;div style="text-indent: 0pt"&gt;&lt;span style="font-family: calibri; color: rgb(0,0,0); font-size: 11pt"&gt;...Find2(System.Collections.Generic.List`1&amp;lt;....Data&amp;gt;,string)&lt;/span&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style="border-bottom: rgb(0,0,0) 0px solid; border-left: rgb(0,0,0) 0px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(51,51,153) 1px solid" width="175"&gt;
&lt;div style="text-indent: 0pt" align="right"&gt;&lt;span style="font-family: calibri; color: rgb(0,0,0); font-size: 11pt"&gt;4.47&lt;/span&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="border-bottom: rgb(51,51,153) 1px solid; border-left: rgb(51,51,153) 1px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(0,0,0) 0px solid" height="14" width="406"&gt;
&lt;div style="text-indent: 0pt"&gt;&lt;span style="font-family: calibri; color: rgb(0,0,0); font-size: 11pt"&gt;...Find3(System.Collections.Generic.List`1&amp;lt;....Data&amp;gt;,string)&lt;/span&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style="border-bottom: rgb(51,51,153) 1px solid; border-left: rgb(0,0,0) 0px solid; border-top: rgb(51,51,153) 1px solid; border-right: rgb(51,51,153) 1px solid" width="175"&gt;
&lt;div style="text-indent: 0pt" align="right"&gt;&lt;span style="font-family: calibri; color: rgb(0,0,0); font-size: 11pt"&gt;3.65&lt;/span&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/p&gt;
&lt;div&gt;That’s something I might put into the category of a micro-optimization AND just
good coding practice.&amp;#160; But is this something that should be caught during a code
review?&amp;#160; I’d say “yes” because logically it all makes sense and none of the solutions
would really hurt maintainability or readability of the code.
&lt;/div&gt;
&lt;div&gt;&amp;#160;
&lt;/div&gt;
&lt;div&gt;So, I’d tag this as a good coding practice.&amp;#160; Other thoughts on the topic?
&lt;/div&gt;
&lt;div&gt;&amp;#160;
&lt;/div&gt;
&lt;div&gt;Enjoy!
&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;</description>
      <comments>http://www.samuraiprogrammer.com/blog/CommentView,guid,9d87b777-0aac-438c-9b47-91e479fea03a.aspx</comments>
      <category>.NET</category>
      <category>Best Practice</category>
      <category>C#</category>
      <category>Code Reviews</category>
      <category>Development</category>
      <category>Performance</category>
    </item>
    <item>
      <trackback:ping>http://www.samuraiprogrammer.com/blog/Trackback.aspx?guid=7e3dbca2-67a5-43c1-91d9-af075409b9c9</trackback:ping>
      <pingback:server>http://www.samuraiprogrammer.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.samuraiprogrammer.com/blog/PermaLink,guid,7e3dbca2-67a5-43c1-91d9-af075409b9c9.aspx</pingback:target>
      <dc:creator>Greg Varveris</dc:creator>
      <wfw:comment>http://www.samuraiprogrammer.com/blog/CommentView,guid,7e3dbca2-67a5-43c1-91d9-af075409b9c9.aspx</wfw:comment>
      <wfw:commentRss>http://www.samuraiprogrammer.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=7e3dbca2-67a5-43c1-91d9-af075409b9c9</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <a href="http://www.samuraiprogrammer.com/blog/2010/07/29/AreYouReadyForYourNextChallengeWereHiring.aspx" target="_blank">
            <img style="border-right-width: 0px; margin: 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="11954221481914068549johnny_automatic_mister_fix_it_svg_hi" border="0" alt="11954221481914068549johnny_automatic_mister_fix_it_svg_hi" align="left" src="http://www.samuraiprogrammer.com/blog/content/binary/WindowsLiveWriter/FixingtheDynamicControlsPlaceholdercontr_1B28/11954221481914068549johnny_automatic_mister_fix_it_svg_hi_8904f347-29ea-413f-bb83-420c018312a1.png" width="124" height="114" /> In
my job as a PFE</a> for <a href="http://www.microsoft.com">Microsoft</a>, I read,
review and fix a lot of code.  A lot of code.  It’s a large part of what
I love about my job.  The code is generally written by large corporations or <a href="http://www.codinghorror.com/blog/2008/12/the-problem-with-logging.html" target="_blank">for
public websites</a>.  Every now and again I’ll get pinged on an issue and after
troubleshooting the issue, it’s pretty clear that the core issue is with some community
code.  When I say community code, in this instance, I don’t mean a CodeProject
or CodePlex project.  In this case, I am referring to a control that <a href="http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx" target="_blank">Denis
Bauer created and then made available to the community on his website – the “DynamicControlsPlaceholder”
control</a>.  This is a great little control that inherits from a PlaceHolder
and allows you to  create dynamic controls on the fly and then it will persist
the controls you add on subsequent requests – like a postback.
</p>
        <h3>The Problem
</h3>
        <p>
The customer was experiencing a problem that could only be replicated in a web farm
when they don’t turn on <a href="http://stackoverflow.com/questions/1040025/difference-between-session-affinity-and-sticky-session" target="_blank">sticky
sessions</a>.  They found that when a request went from one server to another
server in their farm they would get a FileNotFoundException with the following details:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">Type Of Exception:FileNotFoundException<br />
Message:Error on page http://blahblahblah.aspx<br />
Exception Information:System.IO.FileNotFoundException: 
<br />
Could not load file or assembly 'App_Web_myusercontrol.ascx.cc671b29.ypmqvhaw, 
<br />
Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. 
<br />
The system cannot find the file specified.<br />
File name: 'App_Web_myusercontrol.ascx.cc671b29.ypmqvhaw, 
<br />
Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'<br />
at System.RuntimeTypeHandle.GetTypeByName(String name, 
<br />
Boolean throwOnError, 
<br />
Boolean ignoreCase, 
<br />
Boolean reflectionOnly, 
<br />
StackCrawlMark&amp; stackMark)<br />
...<br />
at DynamicControlsPlaceholder.RestoreChildStructure(Pair persistInfo, 
<br />
Control parent)<br />
at DynamicControlsPlaceholder.LoadViewState(Object savedState) 
<br />
at System.Web.UI.Control.LoadViewStateRecursive(Object savedState)<br />
...<br />
at System.Web.UI.Control.LoadViewStateRecursive(Object savedState)<br />
at System.Web.UI.Page.LoadAllState()<br />
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, 
<br />
Boolean includeStagesAfterAsyncPoint)</pre>
          <br />
        </div>
        <p>
So, we can gleam a few things from the error details:
</p>
        <ul>
          <li>
They are using the ASP.NET website model (the “app_web_….dll” assembly is the clue). 
</li>
          <li>
The error is occurring in the RestoreChildStructure method of the DynamicControlsPlaceholder
control. 
</li>
        </ul>
        <h3>The Research
</h3>
        <p>
The way that ASP.NET Websites work is that each component of your site can be compiled
into a separate assembly.  The assembly name is randomly generated.  This
also means that on two servers, the name of the assemblies can end up being different. 
So, an assumption to make is that something is trying to load an assembly by its name. 
If we look at the RestoreChildStructure method, we see the following:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <br />
Type ucType = Type.GetType(typeName[1], <span style="color: #0000ff">true</span>, <span style="color: #0000ff">true</span>);<br /><br /><span style="color: #0000ff">try</span><br />
{<br />
MethodInfo mi = <span style="color: #0000ff">typeof</span>(Page).GetMethod(<span style="color: #006080">"LoadControl"</span>, 
<br /><span style="color: #0000ff">new</span> Type[2] { <span style="color: #0000ff">typeof</span>(Type), <span style="color: #0000ff">typeof</span>(<span style="color: #0000ff">object</span>[])
});<br />
control = (Control) mi.Invoke(<span style="color: #0000ff">this</span>.Page, <span style="color: #0000ff">new</span><span style="color: #0000ff">object</span>[2]
{ ucType, <span style="color: #0000ff">null</span> });<br />
}<br /><span style="color: #0000ff">catch</span> (Exception e)<br />
{<br /><span style="color: #0000ff">throw</span><span style="color: #0000ff">new</span> ArgumentException(String.Format(<span style="color: #006080">"The
type '{0}' …"</span>, 
<br />
ucType.ToString()), e);<br />
}</pre>
          <br />
        </div>
        <p>
The important thing to look at here is the Type.GetType(…) call.  Since the code
for the control is in a separate assembly from everything else, the “typeName[1]”
value <strong>MUST BE A FULLY QUALIFIED ASSEMBLY NAME</strong>.  From the exception
details, we can see that it is attempting to load the type from the following string:
</p>
        <blockquote>
          <p>
            <strong>App_Web_myusercontrol.ascx.cc671b29.ypmqvhaw, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null</strong>
          </p>
        </blockquote>
        <p>
The “typeName[1]” variable is loaded from ViewState because that’s where the control
persists its child structure.  So, for some reason the fully qualified assembly
name is stored in ViewState.  If we look at the code that inserts the value into
ViewState (in the PersistChildStructure(…) method), we see:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <br />
typeName = <span style="color: #006080">"UC:"</span> + control.GetType().AssemblyQualifiedName; </pre>
          <br />
        </div>
        <p>
So, here we see the AssemblyQualifiedName is being stored into ViewState – which is
then used to persist the controls across postback using the above code.  As I
mentioned, this won’t work with an ASP.NET website hosted in a web farm because the
assembly qualified name will probably be different from server to server.  <a href="http://support.microsoft.com/kb/829743" target="_blank">We
even have a KB article that discusses this issue somewhat</a>.  
</p>
        <h3>The Fix
</h3>
        <p>
Fortunately, the fix is pretty simple.  
</p>
        <p>
First, we need to store the path to the User Control instead of the AQN in ViewState. 
To do this, you can comment out the “typeName = ….” line from directly above and replace
it with:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <br />
UserControl uc = control <span style="color: #0000ff">as</span> UserControl;<br />
typeName = <span style="color: #006080">"UC:"</span> + uc.AppRelativeVirtualPath;</pre>
          <br />
        </div>
        <p>
So, now we store the path to the UserControl in ViewState.  Then, we need to
fix the code that actually loads the control.  Replace the code from above in
the RestoreChildStructure(…) method with this code:
</p>
        <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
          <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
            <br />
            <span style="color: #0000ff">string</span> path = typeName[1];<br /><br /><span style="color: #0000ff">try</span><br />
{<br />
control = Page.LoadControl(path);<br />
}<br /><span style="color: #0000ff">catch</span> (Exception e)<br />
{<br /><span style="color: #0000ff">throw</span><span style="color: #0000ff">new</span> ArgumentException(String.Format(<br /><span style="color: #006080">"The type '{0}' cannot be recreated from ViewState"</span>, 
<br />
path), e);<br />
}</pre>
          <br />
        </div>
        <p>
That’s all there is to it.  Just load the user control from where it is being
stored in the site and ASP.NET will take care of loading the appropriate assembly.
</p>
        <p>
Enjoy!
</p>
      </body>
      <title>Fixing the DynamicControlsPlaceholder control – Making the community better</title>
      <guid isPermaLink="false">http://www.samuraiprogrammer.com/blog/PermaLink,guid,7e3dbca2-67a5-43c1-91d9-af075409b9c9.aspx</guid>
      <link>http://www.samuraiprogrammer.com/blog/2010/08/14/FixingTheDynamicControlsPlaceholderControlMakingTheCommunityBetter.aspx</link>
      <pubDate>Sat, 14 Aug 2010 17:45:39 GMT</pubDate>
      <description>&lt;p&gt;
&lt;a href="http://www.samuraiprogrammer.com/blog/2010/07/29/AreYouReadyForYourNextChallengeWereHiring.aspx" target="_blank"&gt;&lt;img style="border-right-width: 0px; margin: 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="11954221481914068549johnny_automatic_mister_fix_it_svg_hi" border="0" alt="11954221481914068549johnny_automatic_mister_fix_it_svg_hi" align="left" src="http://www.samuraiprogrammer.com/blog/content/binary/WindowsLiveWriter/FixingtheDynamicControlsPlaceholdercontr_1B28/11954221481914068549johnny_automatic_mister_fix_it_svg_hi_8904f347-29ea-413f-bb83-420c018312a1.png" width="124" height="114" /&gt; In
my job as a PFE&lt;/a&gt; for &lt;a href="http://www.microsoft.com"&gt;Microsoft&lt;/a&gt;, I read,
review and fix a lot of code.&amp;#160; A lot of code.&amp;#160; It’s a large part of what
I love about my job.&amp;#160; The code is generally written by large corporations or &lt;a href="http://www.codinghorror.com/blog/2008/12/the-problem-with-logging.html" target="_blank"&gt;for
public websites&lt;/a&gt;.&amp;#160; Every now and again I’ll get pinged on an issue and after
troubleshooting the issue, it’s pretty clear that the core issue is with some community
code.&amp;#160; When I say community code, in this instance, I don’t mean a CodeProject
or CodePlex project.&amp;#160; In this case, I am referring to a control that &lt;a href="http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx" target="_blank"&gt;Denis
Bauer created and then made available to the community on his website – the “DynamicControlsPlaceholder”
control&lt;/a&gt;.&amp;#160; This is a great little control that inherits from a PlaceHolder
and allows you to&amp;#160; create dynamic controls on the fly and then it will persist
the controls you add on subsequent requests – like a postback.
&lt;/p&gt;
&lt;h3&gt;The Problem
&lt;/h3&gt;
&lt;p&gt;
The customer was experiencing a problem that could only be replicated in a web farm
when they don’t turn on &lt;a href="http://stackoverflow.com/questions/1040025/difference-between-session-affinity-and-sticky-session" target="_blank"&gt;sticky
sessions&lt;/a&gt;.&amp;#160; They found that when a request went from one server to another
server in their farm they would get a FileNotFoundException with the following details:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;Type Of Exception:FileNotFoundException&lt;br /&gt;
Message:Error on page http://blahblahblah.aspx&lt;br /&gt;
Exception Information:System.IO.FileNotFoundException: 
&lt;br /&gt;
Could not load file or assembly 'App_Web_myusercontrol.ascx.cc671b29.ypmqvhaw, 
&lt;br /&gt;
Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. 
&lt;br /&gt;
The system cannot find the file specified.&lt;br /&gt;
File name: 'App_Web_myusercontrol.ascx.cc671b29.ypmqvhaw, 
&lt;br /&gt;
Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'&lt;br /&gt;
at System.RuntimeTypeHandle.GetTypeByName(String name, 
&lt;br /&gt;
Boolean throwOnError, 
&lt;br /&gt;
Boolean ignoreCase, 
&lt;br /&gt;
Boolean reflectionOnly, 
&lt;br /&gt;
StackCrawlMark&amp;amp; stackMark)&lt;br /&gt;
...&lt;br /&gt;
at DynamicControlsPlaceholder.RestoreChildStructure(Pair persistInfo, 
&lt;br /&gt;
Control parent)&lt;br /&gt;
at DynamicControlsPlaceholder.LoadViewState(Object savedState) 
&lt;br /&gt;
at System.Web.UI.Control.LoadViewStateRecursive(Object savedState)&lt;br /&gt;
...&lt;br /&gt;
at System.Web.UI.Control.LoadViewStateRecursive(Object savedState)&lt;br /&gt;
at System.Web.UI.Page.LoadAllState()&lt;br /&gt;
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, 
&lt;br /&gt;
Boolean includeStagesAfterAsyncPoint)&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
So, we can gleam a few things from the error details:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
They are using the ASP.NET website model (the “app_web_….dll” assembly is the clue). 
&lt;/li&gt;
&lt;li&gt;
The error is occurring in the RestoreChildStructure method of the DynamicControlsPlaceholder
control. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Research
&lt;/h3&gt;
&lt;p&gt;
The way that ASP.NET Websites work is that each component of your site can be compiled
into a separate assembly.&amp;#160; The assembly name is randomly generated.&amp;#160; This
also means that on two servers, the name of the assemblies can end up being different.&amp;#160;
So, an assumption to make is that something is trying to load an assembly by its name.&amp;#160;
If we look at the RestoreChildStructure method, we see the following:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;
&lt;br /&gt;
Type ucType = Type.GetType(typeName[1], &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;);&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;try&lt;/span&gt;
&lt;br /&gt;
{&lt;br /&gt;
MethodInfo mi = &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Page).GetMethod(&lt;span style="color: #006080"&gt;&amp;quot;LoadControl&amp;quot;&lt;/span&gt;, 
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Type[2] { &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Type), &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt;[])
});&lt;br /&gt;
control = (Control) mi.Invoke(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Page, &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; &lt;span style="color: #0000ff"&gt;object&lt;/span&gt;[2]
{ ucType, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; });&lt;br /&gt;
}&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;catch&lt;/span&gt; (Exception e)&lt;br /&gt;
{&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ArgumentException(String.Format(&lt;span style="color: #006080"&gt;&amp;quot;The
type '{0}' …&amp;quot;&lt;/span&gt;, 
&lt;br /&gt;
ucType.ToString()), e);&lt;br /&gt;
}&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
The important thing to look at here is the Type.GetType(…) call.&amp;#160; Since the code
for the control is in a separate assembly from everything else, the “typeName[1]”
value &lt;strong&gt;MUST BE A FULLY QUALIFIED ASSEMBLY NAME&lt;/strong&gt;.&amp;#160; From the exception
details, we can see that it is attempting to load the type from the following string:
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;App_Web_myusercontrol.ascx.cc671b29.ypmqvhaw, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null&lt;/strong&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
The “typeName[1]” variable is loaded from ViewState because that’s where the control
persists its child structure.&amp;#160; So, for some reason the fully qualified assembly
name is stored in ViewState.&amp;#160; If we look at the code that inserts the value into
ViewState (in the PersistChildStructure(…) method), we see:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;
&lt;br /&gt;
typeName = &lt;span style="color: #006080"&gt;&amp;quot;UC:&amp;quot;&lt;/span&gt; + control.GetType().AssemblyQualifiedName; &lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
So, here we see the AssemblyQualifiedName is being stored into ViewState – which is
then used to persist the controls across postback using the above code.&amp;#160; As I
mentioned, this won’t work with an ASP.NET website hosted in a web farm because the
assembly qualified name will probably be different from server to server.&amp;#160; &lt;a href="http://support.microsoft.com/kb/829743" target="_blank"&gt;We
even have a KB article that discusses this issue somewhat&lt;/a&gt;.&amp;#160; 
&lt;/p&gt;
&lt;h3&gt;The Fix
&lt;/h3&gt;
&lt;p&gt;
Fortunately, the fix is pretty simple.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
First, we need to store the path to the User Control instead of the AQN in ViewState.&amp;#160;
To do this, you can comment out the “typeName = ….” line from directly above and replace
it with:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;
&lt;br /&gt;
UserControl uc = control &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; UserControl;&lt;br /&gt;
typeName = &lt;span style="color: #006080"&gt;&amp;quot;UC:&amp;quot;&lt;/span&gt; + uc.AppRelativeVirtualPath;&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
So, now we store the path to the UserControl in ViewState.&amp;#160; Then, we need to
fix the code that actually loads the control.&amp;#160; Replace the code from above in
the RestoreChildStructure(…) method with this code:
&lt;/p&gt;
&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;
&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; path = typeName[1];&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;try&lt;/span&gt;
&lt;br /&gt;
{&lt;br /&gt;
control = Page.LoadControl(path);&lt;br /&gt;
}&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;catch&lt;/span&gt; (Exception e)&lt;br /&gt;
{&lt;br /&gt;
&lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ArgumentException(String.Format(&lt;br /&gt;
&lt;span style="color: #006080"&gt;&amp;quot;The type '{0}' cannot be recreated from ViewState&amp;quot;&lt;/span&gt;, 
&lt;br /&gt;
path), e);&lt;br /&gt;
}&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;
That’s all there is to it.&amp;#160; Just load the user control from where it is being
stored in the site and ASP.NET will take care of loading the appropriate assembly.
&lt;/p&gt;
&lt;p&gt;
Enjoy!
&lt;/p&gt;</description>
      <comments>http://www.samuraiprogrammer.com/blog/CommentView,guid,7e3dbca2-67a5-43c1-91d9-af075409b9c9.aspx</comments>
      <category>ASP.NET</category>
      <category>Development</category>
      <category>Premier Field Engineer (PFE)</category>
    </item>
  </channel>
</rss>