<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://www.pluralsight.com/community/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title type="html">Security Briefs</title><subtitle type="html">by Keith Brown</subtitle><id>http://www.pluralsight.com/community/blogs/keith/atom.aspx</id><link rel="alternate" type="text/html" href="http://www.pluralsight.com/community/blogs/keith/default.aspx" /><link rel="self" type="application/atom+xml" href="http://www.pluralsight.com/community/blogs/keith/atom.aspx" /><generator uri="http://communityserver.org" version="4.0.30619.63">Community Server</generator><updated>2008-07-30T10:23:27Z</updated><entry><title>Sarah Palin and Security Questions</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/10/09/sarah-palin-and-security-questions.aspx" /><id>/community/blogs/keith/archive/2008/10/09/sarah-palin-and-security-questions.aspx</id><published>2008-10-09T08:09:10Z</published><updated>2008-10-09T08:09:10Z</updated><content type="html">&lt;p&gt;I&amp;#39;ve always looked at &lt;a href="http://goodsecurityquestions.com" target="_blank"&gt;security questions&lt;/a&gt; used to automate user password recovery with &lt;a href="http://www.pluralsight.com/community/blogs/keith/archive/2006/05/24/24964.aspx" target="_blank"&gt;quite a bit of skepticism&lt;/a&gt;. What&amp;#39;s the point of requiring strong passwords if you allow anyone to reset the password on an account by answering a (potentially inane) question? And just how many good security questions are there, and how many web sites will ask similar questions, allowing the owner of one web site to reset a user&amp;#39;s password at another site that uses the same question? I&amp;#39;m pretty sure that the typical user will tend to select the same security question if it&amp;#39;s available at multiple sites. In many web sites I&amp;#39;ve seen, the security question is clearly the weak link in the chain.&lt;/p&gt; &lt;p&gt;Apparently &lt;a href="http://voices.washingtonpost.com/securityfix/2008/10/son_of_tenn_lawmaker_indicted.html?hpid=news-col-blogs" target="_blank"&gt;a fellow recently was indicted&lt;/a&gt; on charges of &lt;a href="http://blog.wired.com/27bstroke6/2008/09/palin-e-mail-ha.html" target="_blank"&gt;hacking&lt;/a&gt; into the Republican vice presidential nominee&amp;#39;s Yahoo &lt;a href="http://wikileaks.org/wiki/VP_contender_Sarah_Palin_hacked" target="_blank"&gt;email account&lt;/a&gt;, by simply doing some research on the Internet to find her birthday, zip code, and the answer to her security question, &amp;quot;Where did you meet your spouse?&amp;quot; All told the attack reportedly took under an hour to complete.&lt;/p&gt; &lt;p&gt;Given the level of interest in Palin and other public figures, and the large amount of information about them available to the public, it makes sense that they will be some of the easiest targets for attacks like this.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=53812" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author><category term="Security" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Security/default.aspx" /><category term="Geek talk" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Geek+talk/default.aspx" /><category term="Identity" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Identity/default.aspx" /></entry><entry><title>Zermatt in Community Server</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/10/06/zermatt-in-community-server.aspx" /><id>/community/blogs/keith/archive/2008/10/06/zermatt-in-community-server.aspx</id><published>2008-10-06T22:07:17Z</published><updated>2008-10-06T22:07:17Z</updated><content type="html">&lt;p&gt;I&amp;#39;m about to embark on a mission to get Zermatt integrated into pluralsight.com as our single-sign-on solution, and a big part of that is getting our Community Server installation wired into that. I&amp;#39;m curious if anyone else has seen any work being done in this area, or if I&amp;#39;ll be the first?&lt;/p&gt; &lt;p&gt;I plan to blog about my progress (and share it) if there&amp;#39;s not already a built-in solution out there.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=53780" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author><category term="Security" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Security/default.aspx" /><category term="Geek talk" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Geek+talk/default.aspx" /><category term="Identity" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Identity/default.aspx" /></entry><entry><title>Welcome, Kevin Jones!</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/09/11/welcome-kevin-jones.aspx" /><id>/community/blogs/keith/archive/2008/09/11/welcome-kevin-jones.aspx</id><published>2008-09-11T17:13:51Z</published><updated>2008-09-11T17:13:51Z</updated><content type="html">&lt;p&gt;&lt;img src="http://www.pluralsight.com/main/images/instructors/large/kevin_jones.jpg" border="0" alt="" /&gt;&lt;/p&gt; &lt;p&gt;We&amp;#39;ve worked with &lt;a href="http://www.pluralsight.com/community/blogs/kevinj/default.aspx" target="_blank"&gt;Kevin&lt;/a&gt; in our past lives at a previous training company, and we&amp;#39;re glad to say that he&amp;#39;s joined us as a &lt;a href="http://www.pluralsight.com/main/Instructors.aspx" target="_blank"&gt;Pluralsight instructor&lt;/a&gt;. Located in the United Kingdom, Kevin will be helping out in Europe as well as helping to round out our course curriculum, but more on that later!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=52959" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author></entry><entry><title>A tip on using ASP.NET validation controls</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/09/03/a-tip-on-using-asp-net-validation-controls.aspx" /><id>/community/blogs/keith/archive/2008/09/03/a-tip-on-using-asp-net-validation-controls.aspx</id><published>2008-09-03T17:16:35Z</published><updated>2008-09-03T17:16:35Z</updated><content type="html">&lt;p&gt;Executive summary:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;ValidationSummary controls look at the ErrorMessage field to figure out what to display, so always use ErrorMessage in a verbose enough way that it will be helpful from a ValidationSummary control.&lt;/li&gt; &lt;li&gt;If you need a shorter message to display inline (i.e., where the validation control is on the form, as opposed to the ValidationSummary) use the body of the control to define it.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;In the past, I&amp;#39;ve used RequiredFieldValidator controls on my web forms to remind users that certain fields are required. I would set the ErrorMessage to something vanilla like, &amp;quot;This field is required&amp;quot;, or even something simpler like &amp;quot;*&amp;quot; (an asterisk) if I didn&amp;#39;t have much room on the form to display more prose for an error.&lt;/p&gt; &lt;p&gt;A friend was recently testing a new feature that I&amp;#39;d built for our sales team and she had a hard time seeing the little red asterisks that were showing up next to required fields. It felt to her as though she was pushing the submit button on the form but nothing was happening. It was clear that a ValidationSummary control would be helpful, especially if placed close to the submit button for the form.&lt;/p&gt; &lt;p&gt;I&amp;#39;ve been a bit lazy in the past about using ValidationSummary controls, partially because most of my forms are simple enough that they feel a bit redundant. But on a more complicated form, they can be very helpful to guide users back to the places on the form where there&amp;#39;s problems.&lt;/p&gt; &lt;p&gt;So I threw one of those puppies on the form and immediately saw that there was a problem - my error message was set to &amp;quot;*&amp;quot;, which meant that my validation summary was pretty useless - it just displayed a bunch of red asterisks! And in places where I&amp;#39;d used the prose, &amp;quot;This field is required&amp;quot;, well that was pretty useless as an error message in the summary.&lt;/p&gt; &lt;p&gt;After a bit of research and experimentation, I discovered that the ValidationSummary control looks at the ErrorMessage property on each validation control in order to figure out what to display in the summary. So it&amp;#39;s important to use ErrorMessage with a summary in mind! Don&amp;#39;t use text like &amp;quot;*&amp;quot; or &amp;quot;This field is required&amp;quot;. Be more specific so the user can find her way up to the problem field, as in, &amp;quot;PostalCode is required&amp;quot;.&lt;/p&gt; &lt;p&gt;But if you make ErrorMessage verbose so that it&amp;#39;s helpful in a summary, it may make your form really ugly when displayed inline next to the control being validated. The trick is to use the body of the validation control element to specify the inline error message. Then you end up with two messages: a verbose one that&amp;#39;s used in your summary, and a more localized, brief message that shows up right next to the control being validated. Note the asterisk that&amp;#39;s in the body of the RequiredFieldValidator below:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:RequiredFieldValidator&lt;/span&gt;
      &lt;span class="attr"&gt;ErrorMessage&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Zip/postal code is required&amp;quot;&lt;/span&gt;
      &lt;span class="attr"&gt;ControlToValidate&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;#39;txtPostalCode&amp;#39;&lt;/span&gt;
      &lt;span class="attr"&gt;ValidationGroup&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;#39;BasicInfo&amp;#39;&lt;/span&gt;
      &lt;span class="attr"&gt;Display&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Dynamic&amp;quot;&lt;/span&gt;
      &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;#39;server&amp;#39;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;*&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;asp:RequiredFieldValidator&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;#39;ve learned a lesson from all of this. In the future when I use validation controls I&amp;#39;ll always provide a summary-friendly message in the ErrorMessage field, and if I need something different (typically shorter) to display inline, I&amp;#39;ll put it in the body of the validation control element.&lt;/p&gt;
&lt;p&gt;Hope this helps!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=52816" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author><category term="Geek talk" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Geek+talk/default.aspx" /><category term="ASP.NET" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/ASP.NET/default.aspx" /></entry><entry><title>Null Strings in ASP.NET Declarative DataSource Updates</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/08/29/null-strings-in-asp-net-declarative-datasource-updates.aspx" /><id>/community/blogs/keith/archive/2008/08/29/null-strings-in-asp-net-declarative-datasource-updates.aspx</id><published>2008-08-29T15:42:47Z</published><updated>2008-08-29T15:42:47Z</updated><content type="html">&lt;p&gt;I just spent about 15 minutes debugging a problem where a document was getting unexpected nulls where empty strings should have been. Indeed controls like the TextBox have code in them that allows you to set the Text property to null and the TextBox will convert that into an empty string. So it&amp;#39;s a bit counterintuitive that &lt;em&gt;the declarative data source works the opposite way by default&lt;/em&gt;.&lt;/p&gt; &lt;p&gt;When you use a declarative data source to perform a parameterized update that contains string parameters, consider setting ConvertEmptyStringToNull=&amp;#39;false&amp;#39; on your &amp;lt;asp:Parameter&amp;gt; elements, because &lt;em&gt;it&amp;#39;s true by default&lt;/em&gt;! In other words, if a text field contains an empty string, it&amp;#39;ll be sent to your declarative data source not as string.Empty, but as null.&lt;/p&gt; &lt;p&gt;Now I don&amp;#39;t know about you, but I don&amp;#39;t like dealing with nulls if I can avoid it. Especially strings. Unless there&amp;#39;s a clear need to have a null state, I avoid them like the plague not only in my database designs but also in my XML schema designs. Hopefully this helps somebody out!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=52773" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author><category term="Geek talk" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Geek+talk/default.aspx" /><category term="ASP.NET" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/ASP.NET/default.aspx" /></entry><entry><title>Serializable XmlDocument</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/08/18/serializable-xmldocument.aspx" /><id>/community/blogs/keith/archive/2008/08/18/serializable-xmldocument.aspx</id><published>2008-08-19T03:58:00Z</published><updated>2008-08-19T03:58:00Z</updated><content type="html">&lt;p&gt;(&lt;i&gt;Updated 9 Oct 2008:&lt;/i&gt; replaced my custom MemoryStream.CopyUpToSeekPointer() extension method with MemoryStream.ToArray(), a built in method on MemoryStream that I overlooked and should have been using)&lt;/p&gt;
&lt;p&gt;It&amp;#39;s surprising that XmlDocument isn&amp;#39;t marked [Serializable], because it&amp;#39;s very natural to serialize one into a stream. I wanted to put an object into ASP.NET ViewState the other day, and quickly ran into this roadblock, because part of the object included an XmlDocument, which is not serializable. A quick search revealed that most people deal with this problem by storing a string instead. Indeed, that was where I started, but I quickly realized that there are multiple places in my code where I want to do this sort of thing, and I don&amp;#39;t want to have to mess with it in each data structure that contains an XmlDocument.&lt;/p&gt;
&lt;p&gt;So I put together a simple class that holds an XmlDocument and implements ISerializable and called it SerializableXmlDocument. I&amp;#39;m sharing the source code here in the hopes that&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;a) somebody will find it useful, and&lt;/p&gt;
&lt;p&gt;b) somebody smarter than I am will point out how I screwed it up and help me make it better.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;SerializableXmlDocument includes implicit conversion operators to make it easy to convert to/from an XmlDocument. It holds the actual document in a property called Value. This &amp;quot;isomorph&amp;quot; pattern is one that I picked up from &lt;a href="http://www.pluralsight.com/community/blogs/craig/default.aspx" target="_blank"&gt;Craig&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here is SerializableXmlDocument.cs:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Runtime.Serialization;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Xml;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.IO;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Pluralsight.Samples&lt;br /&gt;{&lt;br /&gt;    [Serializable]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SerializableXmlDocument : ISerializable&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; SerializableXmlDocument() { }&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; SerializableXmlDocument(XmlDocument &lt;span class="kwrd"&gt;value&lt;/span&gt;)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.Value = &lt;span class="kwrd"&gt;value&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; XmlDocument Value { get; set; }&lt;br /&gt;&lt;br /&gt;        &lt;span class="preproc"&gt;#region&lt;/span&gt; ISerializable implementation&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; SerializableXmlDocument(SerializationInfo info,&lt;br /&gt;                                       StreamingContext context)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] serializedData = (&lt;span class="kwrd"&gt;byte&lt;/span&gt;[])info.GetValue(&lt;span class="str"&gt;&amp;quot;doc&amp;quot;&lt;/span&gt;,&lt;br /&gt;                &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[]));&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; != serializedData)&lt;br /&gt;                &lt;span class="kwrd"&gt;this&lt;/span&gt;.Value = Deserialize(serializedData);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; GetObjectData(SerializationInfo info,&lt;br /&gt;                                  StreamingContext context)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] serializedData = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; != Value)&lt;br /&gt;                serializedData = Serialize(Value);&lt;br /&gt;            info.AddValue(&lt;span class="str"&gt;&amp;quot;doc&amp;quot;&lt;/span&gt;, serializedData);&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class="preproc"&gt;#region&lt;/span&gt; &lt;span class="kwrd"&gt;implicit&lt;/span&gt; conversion to/from XmlDocument&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;implicit&lt;/span&gt; &lt;span class="kwrd"&gt;operator&lt;/span&gt; SerializableXmlDocument(&lt;br /&gt;            XmlDocument doc)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; SerializableXmlDocument(doc);&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;implicit&lt;/span&gt; &lt;span class="kwrd"&gt;operator&lt;/span&gt; XmlDocument(&lt;br /&gt;            SerializableXmlDocument sdoc)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; sdoc.Value;&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class="preproc"&gt;#region&lt;/span&gt; Xml serialization helper methods&lt;br /&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] Serialize(XmlDocument doc)&lt;br /&gt;        {&lt;br /&gt;            MemoryStream stream = &lt;span class="kwrd"&gt;new&lt;/span&gt; MemoryStream();&lt;br /&gt;            doc.Save(stream);&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; stream.ToArray();&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; XmlDocument Deserialize(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] serializedData)&lt;br /&gt;        {&lt;br /&gt;            XmlDocument doc = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlDocument();&lt;br /&gt;            doc.Load(&lt;span class="kwrd"&gt;new&lt;/span&gt; MemoryStream(serializedData, &lt;span class="kwrd"&gt;false&lt;/span&gt;));&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; doc;&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;
&lt;p&gt;...and here&amp;#39;s a sample object that uses SerializableXmlDocument:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Pluralsight.Samples&lt;br /&gt;{&lt;br /&gt;    [Serializable]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Item&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name { get; set; }&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; SerializableXmlDocument Data { get; set; }&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Print()&lt;br /&gt;        {&lt;br /&gt;            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Name: {0}&amp;quot;&lt;/span&gt;, Name);&lt;br /&gt;            Console.WriteLine(Data.Value.OuterXml);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;
&lt;p&gt;...and here&amp;#39;s a sample program that creates an instance of Item, serializes it, then deserializes it, printing diagnostics along the way to show that it&amp;#39;s working properly.&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Xml;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Runtime.Serialization.Formatters.Binary;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.IO;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Pluralsight.Samples;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; DemoProgram&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)&lt;br /&gt;    {&lt;br /&gt;        XmlDocument doc = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlDocument();&lt;br /&gt;        doc.LoadXml(&lt;span class="str"&gt;&amp;quot;&amp;lt;root&amp;gt;&amp;lt;child&amp;gt;text&amp;lt;/child&amp;gt;&amp;lt;/root&amp;gt;&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;        Item item = &lt;span class="kwrd"&gt;new&lt;/span&gt; Item&lt;br /&gt;        {&lt;br /&gt;            Name = &lt;span class="str"&gt;&amp;quot;Testing 123&amp;quot;&lt;/span&gt;,&lt;br /&gt;            Data = doc,&lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;        &lt;span class="rem"&gt;// print object before serialization&lt;/span&gt;&lt;br /&gt;        item.Print();&lt;br /&gt;&lt;br /&gt;        BinaryFormatter formatter = &lt;span class="kwrd"&gt;new&lt;/span&gt; BinaryFormatter();&lt;br /&gt;        MemoryStream stream = &lt;span class="kwrd"&gt;new&lt;/span&gt; MemoryStream();&lt;br /&gt;        formatter.Serialize(stream, item);&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] serializedItem = stream.CopyUpToSeekPointer();&lt;br /&gt;&lt;br /&gt;        Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Serialized data (base64): {0}&amp;quot;&lt;/span&gt;,&lt;br /&gt;            Convert.ToBase64String(serializedItem));&lt;br /&gt;&lt;br /&gt;        item = (Item)formatter.Deserialize(&lt;br /&gt;            &lt;span class="kwrd"&gt;new&lt;/span&gt; MemoryStream(serializedItem, &lt;span class="kwrd"&gt;false&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt;        &lt;span class="rem"&gt;// print object after deserialization&lt;/span&gt;&lt;br /&gt;        item.Print();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s the output of the previous sample program:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.pluralsight.com/community/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/keith/sample_2D00_output_5F00_2.jpg"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="sample-output" src="http://www.pluralsight.com/community/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/keith/sample_2D00_output_5F00_thumb.jpg" border="0" width="422" height="214" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Flame away!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=52538" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author><category term="Geek talk" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Geek+talk/default.aspx" /><category term="ASP.NET" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/ASP.NET/default.aspx" /></entry><entry><title>Two-way formatted data binding in ASP.NET</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/08/15/two-way-formatted-data-binding-in-asp-net.aspx" /><id>/community/blogs/keith/archive/2008/08/15/two-way-formatted-data-binding-in-asp-net.aspx</id><published>2008-08-15T20:22:37Z</published><updated>2008-08-15T20:22:37Z</updated><content type="html">&lt;p&gt;Two way data binding in ASP.NET is easy, just use the Bind expression and data will flow between your web controls and your data source flawlessly. Until that is, you try to use a format string:&lt;/p&gt; &lt;p&gt;Bind(&amp;quot;AmountCharged&amp;quot;, &amp;quot;{0:C}&amp;quot;)&lt;/p&gt; &lt;p&gt;While this displays just as you&amp;#39;d expect (e.g., $200), it doesn&amp;#39;t do so well when you submit an edit that includes the same value ($200):&lt;/p&gt; &lt;p&gt;&lt;span style="font-weight:normal;font-size:14pt;color:maroon;font-family:&amp;#39;Verdana&amp;#39;;"&gt;&lt;i&gt;Input string was not in a correct format.&lt;/i&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;I searched around and didn&amp;#39;t find much in the way of a clean solution, but I did solve the problem with just a few lines of code. The trick is to handle the data-bound control&amp;#39;s Updating event. Since I was working with a GridView, my solution looked a bit like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:GridView&lt;/span&gt; &lt;span class="attr"&gt;DataSourceID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;#39;myDataSource&amp;#39;&lt;/span&gt;
              &lt;span class="attr"&gt;OnRowUpdating&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;#39;FixFormatting&amp;#39;&lt;/span&gt;
              &lt;span class="attr"&gt;AutoGenerateColumns&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;#39;false&amp;#39;&lt;/span&gt;
              &lt;span class="attr"&gt;CellPadding&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;3&amp;quot; ...&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Notice the OnRowUpdating handler that I&amp;#39;ve installed in my grid view. That code looks like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; FixFormatting(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, GridViewUpdateEventArgs args)
{
    &lt;span class="kwrd"&gt;decimal&lt;/span&gt; amountPaid = ParseDecimal((&lt;span class="kwrd"&gt;string&lt;/span&gt;)args.NewValues[&lt;span class="str"&gt;&amp;quot;AmountPaid&amp;quot;&lt;/span&gt;]);
    args.NewValues[&lt;span class="str"&gt;&amp;quot;AmountPaid&amp;quot;&lt;/span&gt;] = amountPaid;
}&lt;/pre&gt;
&lt;p&gt;When you handle this event, you&amp;#39;re given a dictionary of old and new values, which appear to come directly from the controls (in my case, a TextBox was used to gather the updated data AmountPaid, so the type of object that I found in NewValues[&amp;quot;AmountPaid&amp;quot;] was a string. I wrote a little helper method called ParseDecimal that parses a string into a decimal value, allowing currency characters, decimal points, and thousands separators. I also allowed a blank value to indicate zero:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;decimal&lt;/span&gt; ParseDecimal(&lt;span class="kwrd"&gt;string&lt;/span&gt; &lt;span class="kwrd"&gt;value&lt;/span&gt;)
{
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(&lt;span class="kwrd"&gt;value&lt;/span&gt;))
        &lt;span class="kwrd"&gt;return&lt;/span&gt; 0;
    &lt;span class="kwrd"&gt;return&lt;/span&gt; Decimal.Parse(&lt;span class="kwrd"&gt;value&lt;/span&gt;,
        NumberStyles.AllowThousands |
        NumberStyles.AllowDecimalPoint |
        NumberStyles.AllowCurrencySymbol,
        CultureInfo.InstalledUICulture);
}
&lt;/pre&gt;
&lt;p&gt;This solved the problem quite nicely. Now two-way binding works with formatted data.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=52504" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author><category term="Geek talk" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Geek+talk/default.aspx" /><category term="ASP.NET" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/ASP.NET/default.aspx" /></entry><entry><title>Where to get Password Minder</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/08/05/where-to-get-password-minder.aspx" /><id>/community/blogs/keith/archive/2008/08/05/where-to-get-password-minder.aspx</id><published>2008-08-05T17:00:00Z</published><updated>2008-08-05T17:00:00Z</updated><content type="html">&lt;p&gt;We recently updated our website and some links have broken as a result. Here&amp;#39;s the place you should go to get the latest version of Password Minder:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://mercury.pluralsight.com/tools.aspx"&gt;http://mercury.pluralsight.com/tools.aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sorry for any inconvenience!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=52369" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author><category term="Security" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Security/default.aspx" /><category term="Geek talk" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Geek+talk/default.aspx" /><category term="Identity" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Identity/default.aspx" /></entry><entry><title>Better exception reporting in ASP.NET part 2</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/08/04/better-exception-reporting-in-asp-net-part-2.aspx" /><id>/community/blogs/keith/archive/2008/08/04/better-exception-reporting-in-asp-net-part-2.aspx</id><published>2008-08-04T14:11:14Z</published><updated>2008-08-04T14:11:14Z</updated><content type="html">&lt;p&gt;This is the third post in a series.&lt;/p&gt; &lt;p&gt;The &lt;a href="http://www.pluralsight.com/community/blogs/keith/archive/2008/08/01/asp-net-health-monitoring-doesn-t-log-inner-exception-stack-trace.aspx" target="_blank"&gt;first post&lt;/a&gt; described the problem: ASP.NET wasn&amp;#39;t reporting inner exception stack traces.&lt;/p&gt; &lt;p&gt;The &lt;a href="http://www.pluralsight.com/community/blogs/keith/archive/2008/08/01/better-exception-reporting-in-asp-net.aspx" target="_blank"&gt;second post&lt;/a&gt; described my solution.&lt;/p&gt; &lt;p&gt;This post shows the code I used to solve the problem: a custom email provider for the Health Monitoring system in ASP.NET. Enjoy!&lt;/p&gt; &lt;p&gt;Here&amp;#39;s the provider. Note that I opted *not* to build a buffering provider to keep things simple:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyMailWebEventProvider : WebEventProvider
{
    &lt;span class="kwrd"&gt;string&lt;/span&gt; to;
    &lt;span class="kwrd"&gt;string&lt;/span&gt; from;
    &lt;span class="kwrd"&gt;string&lt;/span&gt; subjectPrefix;

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Initialize(&lt;span class="kwrd"&gt;string&lt;/span&gt; name,
        NameValueCollection config)
    {
        &lt;span class="kwrd"&gt;base&lt;/span&gt;.Initialize(name, config);

        to = GetAndRemoveStringAttribute(config, &lt;span class="str"&gt;&amp;quot;to&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;true&lt;/span&gt;);
        from = GetAndRemoveStringAttribute(config, &lt;span class="str"&gt;&amp;quot;from&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;true&lt;/span&gt;);
        subjectPrefix = GetAndRemoveStringAttribute(config,
            &lt;span class="str"&gt;&amp;quot;subjectPrefix&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;false&lt;/span&gt;);
    }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ProcessEvent(WebBaseEvent raisedEvent)
    {
        SendMail(raisedEvent);
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SendMail(WebBaseEvent raisedEvent)
    {
        &lt;span class="kwrd"&gt;string&lt;/span&gt; subject = ComputeEmailSubject(raisedEvent);
        &lt;span class="kwrd"&gt;string&lt;/span&gt; body = ComputeEmailBody(raisedEvent);

        MailMessage msg = &lt;span class="kwrd"&gt;new&lt;/span&gt; MailMessage(from, to, subject, body);
        &lt;span class="kwrd"&gt;new&lt;/span&gt; SmtpClient().Send(msg);
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ComputeEmailBody(WebBaseEvent raisedEvent)
    {
        WebRequestErrorEvent errorEvent =
            raisedEvent &lt;span class="kwrd"&gt;as&lt;/span&gt; WebRequestErrorEvent;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; != errorEvent)
            &lt;span class="kwrd"&gt;return&lt;/span&gt; ErrorEventFormattingHelper.FormatRequestErrorEvent(errorEvent);
        &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; raisedEvent.ToString();
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ComputeEmailSubject(WebBaseEvent raisedEvent)
    {
        StringBuilder subjectBuilder = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();

        &lt;span class="rem"&gt;// surface some details in subject about error events&lt;/span&gt;
        WebBaseErrorEvent errorEvent = raisedEvent &lt;span class="kwrd"&gt;as&lt;/span&gt; WebBaseErrorEvent;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; != errorEvent)
        {
            Exception unhandledException = errorEvent.ErrorException;

            &lt;span class="rem"&gt;// drill through reflection exceptions to show the root cause&lt;/span&gt;
            TargetInvocationException invocationException =
                unhandledException &lt;span class="kwrd"&gt;as&lt;/span&gt; TargetInvocationException;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; != invocationException)
            {
                Exception innerException =
                    DrillIntoTargetInvocationException(invocationException);
                subjectBuilder.AppendFormat(&lt;span class="str"&gt;&amp;quot;{0}&amp;quot;&lt;/span&gt;,
                    (innerException ?? invocationException).GetType().Name);
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; != innerException)
                    subjectBuilder.Append(&lt;span class="str"&gt;&amp;quot; (via reflection)&amp;quot;&lt;/span&gt;);
            }
            &lt;span class="kwrd"&gt;else&lt;/span&gt; subjectBuilder.Append(unhandledException.GetType().Name);
        }

        &lt;span class="rem"&gt;// if we&amp;#39;ve not got anything better&lt;/span&gt;
        &lt;span class="rem"&gt;// just show the event type in the subject&lt;/span&gt;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (0 == subjectBuilder.Length)
            subjectBuilder.AppendFormat(&lt;span class="str"&gt;&amp;quot;Event type: {0}&amp;quot;&lt;/span&gt;,
                raisedEvent.GetType().Name);

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(subjectPrefix)) {
            subjectBuilder.Insert(0, &lt;span class="str"&gt;&amp;#39; &amp;#39;&lt;/span&gt;);
            subjectBuilder.Insert(0, subjectPrefix);
        }
        &lt;span class="kwrd"&gt;return&lt;/span&gt; subjectBuilder.ToString();
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Reflection often hides exception details, so we try to drill down&lt;/span&gt;
    &lt;span class="rem"&gt;/// through the plumbing exceptions to find a likely cause&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;private&lt;/span&gt; Exception DrillIntoTargetInvocationException(
        TargetInvocationException outerException)
    {
        Exception innerException = outerException.InnerException;
        TargetInvocationException innerInvocationException =
            innerException &lt;span class="kwrd"&gt;as&lt;/span&gt; TargetInvocationException;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; != innerInvocationException)
            &lt;span class="kwrd"&gt;return&lt;/span&gt; DrillIntoTargetInvocationException(innerInvocationException);
        &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; != innerException)
            &lt;span class="kwrd"&gt;return&lt;/span&gt; innerException;
        &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetAndRemoveStringAttribute(NameValueCollection config,
        &lt;span class="kwrd"&gt;string&lt;/span&gt; attributeName, &lt;span class="kwrd"&gt;bool&lt;/span&gt; required)
    {
        &lt;span class="kwrd"&gt;string&lt;/span&gt; &lt;span class="kwrd"&gt;value&lt;/span&gt; = config.Get(attributeName);
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (required &amp;amp;&amp;amp; &lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(&lt;span class="kwrd"&gt;value&lt;/span&gt;))
            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ConfigurationErrorsException(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
                &lt;span class="str"&gt;&amp;quot;Expected attribute {0}, which is missing or empty.&amp;quot;&lt;/span&gt;,
                attributeName));
        config.Remove(attributeName);
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;value&lt;/span&gt;;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Flush()
    {
        &lt;span class="rem"&gt;// nothing to do - this is not a buffering provider&lt;/span&gt;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Shutdown()
    {
        &lt;span class="rem"&gt;// nothing to do here either&lt;/span&gt;
    }
}&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s a helper class that formats the error messages the way I want to see them. Note that I&amp;#39;ve omitted some fields that I personally didn&amp;#39;t care about, and I&amp;#39;ve reordered things a bit, so you might want to tweak this if you&amp;#39;re going to use it in your own system.&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ErrorEventFormattingHelper
{
    &lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; FormatRequestErrorEvent(
        WebRequestErrorEvent errorEvent)
    {
        CustomEventFormatter formatter = 
            &lt;span class="kwrd"&gt;new&lt;/span&gt; CustomEventFormatter();

        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Unhandled Exception in {0}:&amp;quot;&lt;/span&gt;,
            WebBaseEvent.ApplicationInformation
            .ApplicationVirtualPath));
        formatter.Indent();
        EmitExceptionAtAGlance(formatter, 
            errorEvent.ErrorException);
        formatter.RevertIndent();

        formatter.AppendLine();
        formatter.AppendLine(&lt;span class="str"&gt;&amp;quot;Exception stack trace(s):&amp;quot;&lt;/span&gt;);
        EmitExceptionStackTrace(formatter, 
            errorEvent.ErrorException);

        formatter.AppendLine();
        formatter.AppendLine(&lt;span class="str"&gt;&amp;quot;Event information:&amp;quot;&lt;/span&gt;);
        formatter.Indent();
        EmitEventInfo(formatter, errorEvent);
        formatter.RevertIndent();

        formatter.AppendLine();
        formatter.AppendLine(&lt;span class="str"&gt;&amp;quot;Application information:&amp;quot;&lt;/span&gt;);
        formatter.Indent();
        EmitApplicationInfo(formatter, 
            WebBaseEvent.ApplicationInformation);
        formatter.RevertIndent();

        formatter.AppendLine();
        formatter.AppendLine(&lt;span class="str"&gt;&amp;quot;Process/thread information:&amp;quot;&lt;/span&gt;);
        formatter.Indent();
        EmitProcessInfo(formatter, 
            errorEvent.ProcessInformation);
        formatter.RevertIndent();

        formatter.AppendLine();
        formatter.AppendLine(&lt;span class="str"&gt;&amp;quot;Request information:&amp;quot;&lt;/span&gt;);
        formatter.Indent();
        EmitRequestInfo(formatter, 
            errorEvent.RequestInformation);
        formatter.RevertIndent();

        &lt;span class="kwrd"&gt;return&lt;/span&gt; formatter.ToString();
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; EmitEventInfo(
        CustomEventFormatter formatter,
        WebBaseEvent theEvent)
    {
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Event code: {0}&amp;quot;&lt;/span&gt;,
            theEvent.EventCode.ToString(
            CultureInfo.InvariantCulture)));
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Event message: {0}&amp;quot;&lt;/span&gt;, 
            theEvent.Message));
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Event time: {0}&amp;quot;&lt;/span&gt;, 
            theEvent.EventTime.ToString(
            CultureInfo.InvariantCulture)));
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Event ID: {0}&amp;quot;&lt;/span&gt;, 
            theEvent.EventID.ToString(&lt;span class="str"&gt;&amp;quot;N&amp;quot;&lt;/span&gt;, 
            CultureInfo.InvariantCulture)));
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; EmitApplicationInfo(
        CustomEventFormatter formatter, 
        WebApplicationInformation appInfo)
    {
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Application domain: {0}&amp;quot;&lt;/span&gt;, 
            appInfo.ApplicationDomain));
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Application Virtual Path: {0}&amp;quot;&lt;/span&gt;, 
            appInfo.ApplicationVirtualPath));
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Application Physical Path: {0}&amp;quot;&lt;/span&gt;, 
            appInfo.ApplicationPath));
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; EmitProcessInfo(
        CustomEventFormatter formatter, 
        WebProcessInformation webProcessInfo)
    {
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Process ID: {0}&amp;quot;&lt;/span&gt;, 
            webProcessInfo.ProcessID.ToString(
            CultureInfo.InvariantCulture)));
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Process name: {0}&amp;quot;&lt;/span&gt;, 
            webProcessInfo.ProcessName));
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Account name: {0}&amp;quot;&lt;/span&gt;, 
            webProcessInfo.AccountName));
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; EmitRequestInfo(
        CustomEventFormatter formatter, 
        WebRequestInformation webRequestInfo)
    {
        &lt;span class="kwrd"&gt;string&lt;/span&gt; name = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (webRequestInfo.Principal != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            name = webRequestInfo.Principal.Identity.Name;

        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Request URL: {0}&amp;quot;&lt;/span&gt;, 
            webRequestInfo.RequestUrl));
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Request path: {0}&amp;quot;&lt;/span&gt;, 
            webRequestInfo.RequestPath));
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;User name: {0}&amp;quot;&lt;/span&gt;, 
            name ?? &lt;span class="str"&gt;&amp;quot;[ANONYMOUS]&amp;quot;&lt;/span&gt;));
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;User host address: {0}&amp;quot;&lt;/span&gt;, 
            webRequestInfo.UserHostAddress));
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; EmitExceptionAtAGlance(
        CustomEventFormatter formatter, 
        Exception exception)
    {
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Type: {0}&amp;quot;&lt;/span&gt;, 
            exception.GetType().Name));
        formatter.AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(
            &lt;span class="str"&gt;&amp;quot;Message: {0}&amp;quot;&lt;/span&gt;, 
            exception.Message));
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; != exception.InnerException)
        {
            formatter.Indent();
            formatter.AppendLine(&lt;span class="str"&gt;&amp;quot;--&amp;gt;Inner Exception&amp;quot;&lt;/span&gt;);
            EmitExceptionAtAGlance(formatter, 
                exception.InnerException);
            formatter.RevertIndent();
        }
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; EmitExceptionStackTrace(
        CustomEventFormatter formatter, Exception exception)
    {
        formatter.AppendLine(exception.StackTrace);

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; != exception.InnerException)
        {
            &lt;span class="rem"&gt;// no point indenting&lt;/span&gt;
            &lt;span class="rem"&gt;// since stack traces typically wrap like crazy&lt;/span&gt;
            formatter.AppendLine();
            formatter.AppendLine(&lt;span class="str"&gt;&amp;quot;--&amp;gt;Inner exception stack trace:&amp;quot;&lt;/span&gt;);
            EmitExceptionStackTrace(formatter, exception.InnerException);
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;And finally, here&amp;#39;s a helper class that manages indentation levels for the output email message:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomEventFormatter
{
    &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; TabSpaces = 4;

    StringBuilder sb = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; indentLevel;
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; startingNewLine = &lt;span class="kwrd"&gt;true&lt;/span&gt;;

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Indent()
    {
        ++indentLevel;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RevertIndent()
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (indentLevel &amp;gt; 0)
            --indentLevel;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Append(&lt;span class="kwrd"&gt;string&lt;/span&gt; text)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (startingNewLine)
            EmitIndent();
        sb.Append(text);
        startingNewLine = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt; lineOfText)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (startingNewLine)
            EmitIndent();
        EmitIndent();
        sb.AppendLine(lineOfText);
        startingNewLine = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; EmitIndent()
    {
        sb.Append(&lt;span class="str"&gt;&amp;#39; &amp;#39;&lt;/span&gt;, TabSpaces * indentLevel);
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AppendLine()
    {
        AppendLine(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty);
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ToString()
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; sb.ToString();
    }
}
&lt;/pre&gt;
&lt;p&gt;Build this into a library application and reference it in your config file. Here&amp;#39;s an example:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;healthMonitoring&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;providers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;mailWebEventProvider&amp;quot;&lt;/span&gt;
         &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;MyMailWebEventProvider&amp;quot;&lt;/span&gt;
         &lt;span class="attr"&gt;to&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;web-fault@fabrikam.com&amp;quot;&lt;/span&gt;
         &lt;span class="attr"&gt;from&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;website@fabrikam.com&amp;quot;&lt;/span&gt;
         &lt;span class="attr"&gt;buffer&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;false&amp;quot;&lt;/span&gt;
         &lt;span class="attr"&gt;subjectPrefix&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;[WEB-ERROR]&amp;quot;&lt;/span&gt;
       &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;providers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;rules&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;All Errors Email&amp;quot;&lt;/span&gt;
         &lt;span class="attr"&gt;eventName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;All Errors&amp;quot;&lt;/span&gt;
         &lt;span class="attr"&gt;provider&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;mailWebEventProvider&amp;quot;&lt;/span&gt;
         &lt;span class="attr"&gt;profile&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Default&amp;quot;&lt;/span&gt;
         &lt;span class="attr"&gt;minInstances&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;1&amp;quot;&lt;/span&gt;
         &lt;span class="attr"&gt;maxLimit&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Infinite&amp;quot;&lt;/span&gt;
         &lt;span class="attr"&gt;minInterval&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;00:01:00&amp;quot;&lt;/span&gt;
         &lt;span class="attr"&gt;custom&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;rules&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;healthMonitoring&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=52349" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author><category term="Geek talk" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Geek+talk/default.aspx" /><category term="ASP.NET" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/ASP.NET/default.aspx" /></entry><entry><title>Twisted Coronas</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/08/02/twisted-coronas.aspx" /><id>/community/blogs/keith/archive/2008/08/02/twisted-coronas.aspx</id><published>2008-08-02T17:33:51Z</published><updated>2008-08-02T17:33:51Z</updated><content type="html">&lt;p&gt;Okay it&amp;#39;s Saturday, so let me share something completely nontechnical and fun.&lt;/p&gt; &lt;p&gt;What you need to make these cocktails:&lt;/p&gt; &lt;blockquote&gt;Six pack of &lt;a href="http://www.corona.com/" target="_blank"&gt;Corona Extra&lt;/a&gt;&lt;br /&gt;Bottle of &lt;a href="http://www.bacardi.com/us/en-us/products/additionalproducts/bacardilim%C3%B3n?accessibility=true&amp;amp;marketlanguageid=2" target="_blank"&gt;Bacardi Limon&lt;/a&gt;&lt;br /&gt;Lime&lt;br /&gt;Coctail stirrer (a chopstick works fine)&lt;/blockquote&gt; &lt;p&gt;Pop a slice of lime into a Corona and hand to a friend. Have them drink the neck, then refill with Bacardi Limon (putting the lime in first seems to reduce fizzing). Stir and hand back to them so they can drink it down as it fizzes up a bit.&lt;/p&gt; &lt;p&gt;Mixing rum and beer may sound nasty, but this actually results in a very smooth, tasty drink. It&amp;#39;s our favorite accompaniment when we are playing &lt;a href="http://www.xbox.com/en-us/games/r/rockband/" target="_blank"&gt;Rock Band&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;We took this recipe and applied it to one of our other favorite beers as well: &lt;a href="http://www.epinions.com/content_369863855748" target="_blank"&gt;Honey Moon Summer Ale&lt;/a&gt; (also works with &lt;a href="http://en.wikipedia.org/wiki/Blue_Moon_(beer)" target="_blank"&gt;Blue Moon&lt;/a&gt;, or any other typically orange-flavored beer). Just use &lt;a href="http://www.bacardi.com/us/en-us/products/additionalproducts/bacardio?accessibility=true&amp;amp;marketlanguageid=2" target="_blank"&gt;Barcardi O&lt;/a&gt; instead of Limon.&lt;/p&gt; &lt;p&gt;Enjoy!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=52330" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author><category term="42" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/42/default.aspx" /></entry><entry><title>Comments</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/08/01/comments.aspx" /><id>/community/blogs/keith/archive/2008/08/01/comments.aspx</id><published>2008-08-01T21:38:00Z</published><updated>2008-08-01T21:38:00Z</updated><content type="html">&lt;p&gt;We recently switched our blog engine out, and I&amp;#39;m still getting the hang of the new system. Looks like due to a misconfiguration, several comments have been waiting for moderation for days or weeks. If yours was one of them, please accept my apology - I didn&amp;#39;t have email notifications turned on, so I wasn&amp;#39;t being notified that comments were coming in.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve since fixed the problem, so your comments should show up sooner. Sorry for any confusion!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=52316" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author><category term="Geek talk" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Geek+talk/default.aspx" /></entry><entry><title>Better exception reporting in ASP.NET</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/08/01/better-exception-reporting-in-asp-net.aspx" /><id>/community/blogs/keith/archive/2008/08/01/better-exception-reporting-in-asp-net.aspx</id><published>2008-08-01T21:30:00Z</published><updated>2008-08-01T21:30:00Z</updated><content type="html">&lt;p&gt;In &lt;a href="http://www.pluralsight.com/community/blogs/keith/archive/2008/08/01/asp-net-health-monitoring-doesn-t-log-inner-exception-stack-trace.aspx" target="_blank"&gt;my last post&lt;/a&gt;, I commented on how ASP.NET health monitoring doesn&amp;#39;t output stack traces for inner exceptions, which can be problematic due to its heavy reliance on reflection. I spent the morning doing some further spelunking with &lt;a href="http://www.aisto.com/roeder/dotnet/" target="_blank"&gt;reflector&lt;/a&gt;, and my first solution was to implement a custom WebEvent that overrides ToString() to format itself with all of the data I care about. I then overrode the Error event via global.asax and raised my custom event, instead of letting ASP.NET raise its default event. This worked reasonably well with the SimpleMailWebEventProvider, but didn&amp;#39;t seem to change anything at all with the event log provider.&lt;/p&gt;
&lt;p&gt;What I found is that the two providers were using entirely different means to format the events! The email provider calls ToString(bool, bool) on the event to ask it to format itself. But the EventLogWebEventProvider does its own formatting of individual fields of the event. Indeed, its ProcessEvent method has a big list of checks:&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (eventRaised &lt;span class="kwrd"&gt;is&lt;/span&gt; WebBaseErrorEvent)&lt;br /&gt;    AddErrorStuff();&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (eventRaised &lt;span class="kwrd"&gt;is&lt;/span&gt; WebAuthenticationSuccessAuditEvent)&lt;br /&gt;    AddLogonStuff();&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;So it seemed like a better approach would be to write my own provider. I left the event log provider alone, and I wrote a custom email provider to display errors in a more useful way. This also allowed me to drop some fields from the event report that aren&amp;#39;t useful for us. And I was able to construct a much more concise and useful subject line (the subject line that SimpleMailWebEventProvider uses is rather clunky since it assumes it might be spitting out a whole bunch of buffered events in one go).&lt;/p&gt;
&lt;p&gt;Not only does my provider include the stack traces for all of the exceptions in the chain, but in the subject line, I display the type of error that is at the root of the problem. So if I am formatting a TargetInvocationException, I drill into its InnerException chain until I find a different exception type, and display that exception type instead.&lt;/p&gt;
&lt;p&gt;Oh, one other benefit of building the custom provider instead of using a custom WebEvent was that I was then able to remove the Error handler from global.asax. All I had to do was replace the SimpleMailWebEventProvider with my own provider, and I got the behavior I wanted. Now my email notifications include detailed stack traces.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ll post the code for this provider once it&amp;#39;s run for a little while in production and I&amp;#39;m satisfied that it works reasonably well.&lt;/p&gt;
&lt;p&gt;UPDATE: I included the code in my &lt;a href="http://www.pluralsight.com/community/blogs/keith/archive/2008/08/04/better-exception-reporting-in-asp-net-part-2.aspx"&gt;third post&lt;/a&gt; in this series.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=52314" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author><category term="Geek talk" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Geek+talk/default.aspx" /><category term="ASP.NET" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/ASP.NET/default.aspx" /></entry><entry><title>ASP.NET Health Monitoring doesn't log inner exception stack trace</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/08/01/asp-net-health-monitoring-doesn-t-log-inner-exception-stack-trace.aspx" /><id>/community/blogs/keith/archive/2008/08/01/asp-net-health-monitoring-doesn-t-log-inner-exception-stack-trace.aspx</id><published>2008-08-01T17:21:00Z</published><updated>2008-08-01T17:21:00Z</updated><content type="html">&lt;p&gt;This can be a problem, especially when an ObjectDataSource starts throwing exceptions. The stack trace looks the same because of the way the methods are invoked (via reflection) - you end up with a stack trace for a TargetInvocationException, which basically says, &amp;quot;I used reflection to invoke some method, and it threw an exception. See the inner exception for details.&amp;quot;&lt;/p&gt;
&lt;p&gt;ASP.NET&amp;#39;s health monitoring system does list the inner exceptions (apparently up to a maximum depth of two, from spelunking the code with &lt;a href="http://www.aisto.com/roeder/dotnet/"&gt;reflector&lt;/a&gt;), but it does not emit the stack traces for these exceptions, which would be &lt;i&gt;really helpful&lt;/i&gt;. I&amp;#39;ve spent some time this morning trying to figure out how I&amp;#39;d customize things to emit this, and it looks like what I&amp;#39;d have to do is catch the exception and generate a custom WebEvent that overrides ToString(bool, bool) and does everything that WebRequestErrorEvent does, but also generate the inner stack trace.&lt;/p&gt;
&lt;p&gt;That seems a bit ugly. A search for &amp;quot;ASP.NET web event inner exception stack trace&amp;quot; yielded no interesting results, so if you&amp;#39;ve dealt with this and have a cleaner solution, let me know. I&amp;#39;ll post my solution once I get it worked out.&lt;/p&gt;
&lt;p&gt;UPDATE: I ended up &lt;a href="http://www.pluralsight.com/community/blogs/keith/archive/2008/08/01/better-exception-reporting-in-asp-net.aspx"&gt;writing a custom email provider&lt;/a&gt;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=52306" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author><category term="Geek talk" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Geek+talk/default.aspx" /><category term="ASP.NET" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/ASP.NET/default.aspx" /></entry><entry><title>Simulating Email in .NET</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/08/01/simulating-email-in-net.aspx" /><id>/community/blogs/keith/archive/2008/08/01/simulating-email-in-net.aspx</id><published>2008-08-01T16:59:00Z</published><updated>2008-08-01T16:59:00Z</updated><content type="html">&lt;p&gt;I use email as a notification mechanism a lot, and often in class I&amp;#39;ll demo sending email via a technique that I use frequently when developing code. It allows you to simulate sending an email message.&lt;/p&gt;
&lt;p&gt;The trick to doing this is not to hardcode things like host, port, etc. for your SMTP server when you use System.Net.Mail to send mail. Instead, use the default ctor for &lt;a href="http://msdn.microsoft.com/en-us/library/system.net.mail.smtpclient.aspx" target="_blank"&gt;SmtpClient&lt;/a&gt; as I&amp;#39;ve done in the code below.&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="rem"&gt;// note the use of the MailAddress class&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;// this allows me to specify display names as well as email addresses&lt;/span&gt;&lt;br /&gt;    MailAddress from = &lt;span class="kwrd"&gt;new&lt;/span&gt; MailAddress(&lt;span class="str"&gt;&amp;quot;admin@fabrikam.com&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Fabrikam Website&amp;quot;&lt;/span&gt;);&lt;br /&gt;    MailAddress to = &lt;span class="kwrd"&gt;new&lt;/span&gt; MailAddress(&lt;span class="str"&gt;&amp;quot;mari@fabrikam.com&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Mari Joyce&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    MailMessage msg = &lt;span class="kwrd"&gt;new&lt;/span&gt; MailMessage(from, to);&lt;br /&gt;    msg.Subject  = &lt;span class="str"&gt;&amp;quot;Testing 123&amp;quot;&lt;/span&gt;;&lt;br /&gt;    msg.Body = &lt;span class="str"&gt;&amp;quot;This is only a test!&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span class="rem"&gt;// note use of default ctor&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;// this looks in config to figure out how to send mail&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;new&lt;/span&gt; SmtpClient().Send(msg);&lt;br /&gt;}&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;What you&amp;#39;re telling .NET by using the default ctor for SmtpClient is, &amp;quot;please use my config file to figure out how to send mail&amp;quot;. Now you can use the system.net/mailSettings/smtp section in config to specify the details of your mail server, and all of the code in your app that is written to use the default SmtpClient ctor will inherit these settings. Here&amp;#39;s an example of what the config on a production server might look like (if you put passwords in your config files, be sure to &lt;a href="http://msdn.microsoft.com/en-us/library/ms998283.aspx" target="_blank"&gt;encrypt those sections&lt;/a&gt;): &lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.net&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;mailSettings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;smtp&lt;/span&gt; &lt;span class="attr"&gt;deliveryMethod&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Network&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;network&lt;/span&gt; &lt;span class="attr"&gt;host&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;mail.fabrikam.com&amp;quot;&lt;/span&gt;&lt;br /&gt;                 &lt;span class="attr"&gt;port&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;25&amp;quot;&lt;/span&gt;&lt;br /&gt;                 &lt;span class="attr"&gt;userName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;WebsiteMailAccount&amp;quot;&lt;/span&gt;&lt;br /&gt;                 &lt;span class="attr"&gt;password&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;whatever&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;smtp&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;mailSettings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;system.net&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;During development, I use different settings because I don&amp;#39;t usually want to deal with the hassle of installing an SMTP server on my development box. Instead, I want email messages delivered as individual files in a directory on my hard drive (I always have a c:\mail directory on my development box for just this purpose):&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.net&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;mailSettings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;smtp&lt;/span&gt; &lt;span class="attr"&gt;deliveryMethod&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SpecifiedPickupDirectory&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;specifiedPickupDirectory&lt;/span&gt; &lt;span class="attr"&gt;pickupDirectoryLocation&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;c:\mail&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;smtp&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;mailSettings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;system.net&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now when I run the program above, I get a .EML file in my c:\mail directory:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.pluralsight.com/community/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/keith/image_5F00_2.png"&gt;&lt;img style="border-right:0px;border-top:0px;margin:0px 0px 0px 35px;border-left:0px;border-bottom:0px;" alt="image" src="http://www.pluralsight.com/community/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/keith/image_5F00_thumb.png" width="404" border="0" height="230" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Outlook Express is normally registered as the viewer for .EML files, so double-click the file to view it:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.pluralsight.com/community/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/keith/image_5F00_4.png"&gt;&lt;img style="border-right:0px;border-top:0px;margin:0px 0px 0px 35px;border-left:0px;border-bottom:0px;" alt="image" src="http://www.pluralsight.com/community/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/keith/image_5F00_thumb_5F00_1.png" width="292" border="0" height="287" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;If you&amp;#39;ve never seen this method of simulating email before, I hope you find it as useful as I have. Happy coding!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=52305" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author><category term="Geek talk" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Geek+talk/default.aspx" /></entry><entry><title>Controlling column width in a GridView</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/07/30/controlling-column-width-in-a-gridview.aspx" /><id>/community/blogs/keith/archive/2008/07/30/controlling-column-width-in-a-gridview.aspx</id><published>2008-07-30T17:23:27Z</published><updated>2008-07-30T17:23:27Z</updated><content type="html">&lt;p&gt;I&amp;#39;ve been building some internal pages for our sales team here at &lt;a href="http://www.pluralsight.com/main/" target="_blank"&gt;Pluralsight&lt;/a&gt;, and many of those pages make use of the ASP.NET GridView control to display rectangular data. It&amp;#39;s generally a really easy to use control, but I&amp;#39;ve always struggled with getting column widths to look right.&lt;/p&gt;  &lt;p&gt;My goal is to fix the width of each column at design time, and any field that contains text that may be longer than my fixed width should wrap around, taking up more vertical space in the table. If you are trying to accomplish this goal, you might find these tips helpful.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;1) Set up a CssClass for the GridView itself and include the &lt;a href="http://www.w3.org/TR/REC-CSS2/tables.html#fixed-table-layout" target="_blank"&gt;table-layout:fixed&lt;/a&gt; style. This tells the browser that you&amp;#39;re going to specify the width of each cell. You may also want to include the overall width of the grid here as I mention in (3).&lt;/p&gt;    &lt;p&gt;2) The first row of the table sets the width for each cell, and that&amp;#39;s usually the HEADER row, not the item row, so use either HeaderStyle-CssClass or HeaderStyle-Width to set the width of the cell. I wasted a lot of time trying to set the width using the ItemStyle.&lt;/p&gt;    &lt;p&gt;3) Make certain the table itself is wide enough to hold all of the cells. I added up all of my cell widths and used that to set the width via the CssClass attribute on the GridView.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Using these guidelines, I&amp;#39;m having much better luck controlling the layout of my GridView controls. I hope this simple advise helps someone else!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=52286" width="1" height="1"&gt;</content><author><name>keith-brown</name><uri>http://www.pluralsight.com/community/members/keith_2D00_brown/default.aspx</uri></author><category term="Geek talk" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Geek+talk/default.aspx" /><category term="ASP.NET" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/ASP.NET/default.aspx" /></entry></feed>