<?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-08-01T14:38:00Z</updated><entry><title>Zermatt is now Geneva Framework</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/11/26/zermatt-is-now-geneva-framework.aspx" /><id>/community/blogs/keith/archive/2008/11/26/zermatt-is-now-geneva-framework.aspx</id><published>2008-11-26T14:41:00Z</published><updated>2008-11-26T14:41:00Z</updated><content type="html">&lt;p&gt;For those who didn&amp;#39;t attend PDC, the &lt;a href="http://www.pluralsight.com/community/blogs/keith/archive/2008/07/09/introducing-microsoft-code-name-zermatt.aspx"&gt;Zermatt identity framework&lt;/a&gt; has been re-code-named Geneva Framework so that it fits in with the &lt;a href="http://www.microsoft.com/geneva" target="_blank"&gt;Geneva family of products&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/card/archive/2008/11/04/microsoft-geneva-framework.aspx" target="_blank"&gt;Geneva Framework&lt;/a&gt;: a .NET class library called Microsoft.IdentityModel (basically it&amp;#39;s an updated Zermatt)&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/card/archive/2008/11/04/geneva-server-beta.aspx" target="_blank"&gt;Geneva Server&lt;/a&gt;: This is essentially ADFS v2, built on top of the Geneva Framework&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/card/archive/2008/11/18/the-cardspace-geneva-selection-experience.aspx" target="_blank"&gt;Geneva CardSpace&lt;/a&gt;: This is CardSpace v2.&lt;/p&gt;
&lt;p&gt;This link takes you to the &amp;quot;Geneva&amp;quot; landing page at Microsoft, where you&amp;#39;ll find links to all of the bits, as well as the whitepaper v2. The new version of the whitepaper was co-authored by myself and a PM on the Geneva Framework team, Sesha Mani, who added a bunch of new details based on the PDC version of the framework.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=55244" 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>Wells Fargo Opt Out 800 Number</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/10/30/wells-fargo-opt-out-800-number.aspx" /><id>/community/blogs/keith/archive/2008/10/30/wells-fargo-opt-out-800-number.aspx</id><published>2008-10-30T18:04:26Z</published><updated>2008-10-30T18:04:26Z</updated><content type="html">&lt;p&gt;I have been a happy customer of Wells Fargo for a couple of years now, but one thing has always bothered me: being solicited by loosely affiliated companies. Well, I finally found out how to fix this. I called 888.528.8460, which is their &amp;quot;privacy preference line&amp;quot;. From there I was able to opt out of all solicitation for new services.&lt;/p&gt; &lt;p&gt;We&amp;#39;ll see how well it works.&lt;/p&gt; &lt;p&gt;I&amp;#39;m not a crazy environmentalist, but waste makes me cringe. I make it a habit to contact companies that mail me catalogs that I don&amp;#39;t read, telling them to take me off of their lists. I also do little things like bring a couple of bags to the grocery store every time I go in order to avoid generating more plastic waste.&lt;/p&gt; &lt;p&gt;The other day, I was buying my son a sweatshirt in T.J. Maxx, and the clerk popped it into a plastic bag. I said, &amp;quot;Thanks, but I really don&amp;#39;t need that bag.&amp;quot; He promptly balled it up and threw it in the trash. It makes me sad how so many people just don&amp;#39;t get it. If everyone would just think a little bit about this in their daily lives, I think it&amp;#39;d make a big difference for the world we leave to our kids and grandkids.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=54177" 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>PasswordTextBox</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/10/29/passwordtextbox.aspx" /><id>/community/blogs/keith/archive/2008/10/29/passwordtextbox.aspx</id><published>2008-10-29T19:49:54Z</published><updated>2008-10-29T19:49:54Z</updated><content type="html">&lt;p&gt;&lt;a href="http://www.sellsbrothers.com/" target="_blank"&gt;Chris Sells&lt;/a&gt; used to poke fun at me when we worked together in my &lt;a href="http://www.flickr.com/photos/andyrs/240203382/" target="_blank"&gt;former life&lt;/a&gt;. He used to call my security class, &amp;quot;Essential Access Denied&amp;quot;. His point was a good one: when they aren&amp;#39;t applied carefully, security countermeasures often just get in the way of getting work done. I don&amp;#39;t know about you, but password-mode text boxes in web forms have always been one of those annoyances.&lt;/p&gt; &lt;p&gt;I&amp;#39;m not complaining about the fact that I can&amp;#39;t see what I&amp;#39;m typing. I understand and laud that feature, because I don&amp;#39;t want someone looking over my shoulder at the password I&amp;#39;m typing, and this even applies when I&amp;#39;m at home. I love my children, but I certainly don&amp;#39;t want them knowing the password to my bank account!&lt;/p&gt; &lt;p&gt;No, what I&amp;#39;m bothered by is how a typical password text box behaves on a form that may incur multiple post-backs before it&amp;#39;s finally submitted. If you use the built in ASP.NET TextBox control, it purposely does not repopulate the password text, which means if you press a button on the form that performs a post-back, or if you have a multi-page form that posts back on every step, that password disappears, and the user typically has to re-enter it. You could solve this with liberal use of ASP.NET Ajax UpdatePanels, but that adds its own complexities. I wanted a simpler solution.&lt;/p&gt; &lt;p&gt;So I did a little research to see what others had discovered about this problem, and I ended up deriving my own custom control from TextBox to make a much more user-friendly (and developer-friendly) TextBox control. I called it PasswordTextBox, and it acts just like a TextBox in password mode, but it retains the password while still giving the user the same level of protection the standard TextBox supplies.&lt;/p&gt; &lt;p&gt;My PasswordTextBox operates very simply: it stores the password in control state, and renders a series of fixed characters (with the same length as the actual password) into the text box so that it &amp;quot;looks&amp;quot; like the user&amp;#39;s password has been rendered. Since control state is part of view state, and since view state is stored in a hidden field on the form, I encrypt the password before putting it into control state.&lt;/p&gt; &lt;p&gt;The result is quite nice - the user can post your form back as many times as she needs to, perhaps moving back and forth across wizard steps or tabs, and when she finally presses the &amp;quot;Finish&amp;quot; button (or whatever you call the last step of your input form), your code will be able to read the password by simply accessing the Text property on the PasswordTextBox. The user will believe that her password is sitting there on the form while she&amp;#39;s working, as the same number of obfuscated characters will show up in the field as she typed in originally (what she doesn&amp;#39;t know is that those characters aren&amp;#39;t her real password anymore, but what she doesn&amp;#39;t know won&amp;#39;t hurt her!)&lt;/p&gt; &lt;p&gt;Note that to keep this simple, I used DPAPI to encrypt the password, which suited my purposes. But if you have a web farm, that won&amp;#39;t work well at all if you don&amp;#39;t know which machine the user&amp;#39;s going to post back to, so you&amp;#39;ll want to replace that with something more robust. I could see looking up the &amp;lt;machineKey&amp;gt; for entropy, as that tends to be sync&amp;#39;d already across the farm, but I&amp;#39;ve not yet spent the cycles to go down that road, since unfortunately all of the code for generating keys based on that config section are off limits in ASP.NET (most of the useful stuff is marked internal). I don&amp;#39;t think it&amp;#39;d be that hard to do though.&lt;/p&gt; &lt;p&gt;Anyway, without further ado, here&amp;#39;s the code, which you&amp;#39;ll see is quite simple. I&amp;#39;d love feedback, especially if you see any glaring problems with the idea or the implementation!&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; PasswordTextBox : TextBox
{
    &lt;span class="rem"&gt;// unlikely that a string of these would be used for a password&lt;/span&gt;
    &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;char&lt;/span&gt; PasswordPlaceholderChar = &lt;span class="str"&gt;&amp;#39;}&amp;#39;&lt;/span&gt;;

    &lt;span class="kwrd"&gt;string&lt;/span&gt; password; &lt;span class="rem"&gt;// stored encrypted in control state&lt;/span&gt;

    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnInit(EventArgs e)
    {
        &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnInit(e);
        Page.RegisterRequiresControlState(&lt;span class="kwrd"&gt;this&lt;/span&gt;);
    }

    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; SaveControlState()
    {
        &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] encryptedPassword = ProtectPassword(password);

        &lt;span class="kwrd"&gt;object&lt;/span&gt; baseControlState = &lt;span class="kwrd"&gt;base&lt;/span&gt;.SaveControlState();
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; == baseControlState)
            &lt;span class="kwrd"&gt;return&lt;/span&gt; encryptedPassword;
        &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Pair(baseControlState, encryptedPassword);
    }

    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; LoadControlState(&lt;span class="kwrd"&gt;object&lt;/span&gt; savedState)
    {
        &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] encryptedPassword;

        Pair pair = savedState &lt;span class="kwrd"&gt;as&lt;/span&gt; Pair;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; != pair)
        {
            &lt;span class="kwrd"&gt;base&lt;/span&gt;.LoadControlState(pair.First);
            encryptedPassword = pair.Second &lt;span class="kwrd"&gt;as&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[];
        }
        &lt;span class="kwrd"&gt;else&lt;/span&gt; encryptedPassword = savedState &lt;span class="kwrd"&gt;as&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[];

        password = UnprotectPassword(encryptedPassword);
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// This control always uses TextMode=Password&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; TextBoxMode TextMode
    {
        get
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; TextBoxMode.Password;
        }
        set { }
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// TextBox doesn&amp;#39;t render value attribute for TextMode=Password&lt;/span&gt;
    &lt;span class="rem"&gt;/// So we add code that renders a placeholder text instead&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;writer&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AddAttributesToRender(HtmlTextWriter writer)
    {
        &lt;span class="kwrd"&gt;base&lt;/span&gt;.AddAttributesToRender(writer);

        &lt;span class="kwrd"&gt;string&lt;/span&gt; text = Text;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (text.Length &amp;gt; 0)
            writer.AddAttribute(HtmlTextWriterAttribute.Value,
                GetPlaceholderPassword(text));
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// TextBox doesn&amp;#39;t save the &amp;quot;Text&amp;quot; viewstate in&lt;/span&gt;
    &lt;span class="rem"&gt;/// TextMode=Password and we don&amp;#39;t want our behavior to break&lt;/span&gt;
    &lt;span class="rem"&gt;/// if ViewState is turned off so we store the password in&lt;/span&gt;
    &lt;span class="rem"&gt;/// Control State, encrypted with MachineKey&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&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;string&lt;/span&gt; Text
    {
        get
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; password ?? &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;
        }
        set
        {
            &lt;span class="rem"&gt;// this prevents us overwriting the actual&lt;/span&gt;
            &lt;span class="rem"&gt;// password with a placeholder&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(password) &amp;amp;&amp;amp;
                &lt;span class="kwrd"&gt;value&lt;/span&gt;.Equals(GetPlaceholderPassword(password)))
                &lt;span class="kwrd"&gt;return&lt;/span&gt;;

            password = &lt;span class="kwrd"&gt;value&lt;/span&gt;;
        }
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetPlaceholderPassword(&lt;span class="kwrd"&gt;string&lt;/span&gt; realPassword)
    {
        &lt;span class="kwrd"&gt;int&lt;/span&gt; length = 12;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(realPassword))
            length = realPassword.Length;

        StringBuilder sb = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();
        sb.Append(PasswordPlaceholderChar, length);

        &lt;span class="kwrd"&gt;return&lt;/span&gt; sb.ToString();
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] ProtectPassword(&lt;span class="kwrd"&gt;string&lt;/span&gt; password)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(password))
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] cleartext = Encoding.UTF8.GetBytes(password);
        &lt;span class="kwrd"&gt;return&lt;/span&gt; ProtectedData.Protect(cleartext, &lt;span class="kwrd"&gt;null&lt;/span&gt;,
            DataProtectionScope.LocalMachine);
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; UnprotectPassword(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] ciphertext)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; == ciphertext)
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] cleartext = ProtectedData.Unprotect(ciphertext, &lt;span class="kwrd"&gt;null&lt;/span&gt;,
            DataProtectionScope.LocalMachine);
        &lt;span class="kwrd"&gt;return&lt;/span&gt; Encoding.UTF8.GetString(cleartext);
    }
}
&lt;/pre&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=54154" 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="Identity" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/Identity/default.aspx" /><category term="ASP.NET" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/ASP.NET/default.aspx" /></entry><entry><title>Pluralsight On-Demand is now live!</title><link rel="alternate" type="text/html" href="/community/blogs/keith/archive/2008/10/29/pluralsight-on-demand-is-now-live.aspx" /><id>/community/blogs/keith/archive/2008/10/29/pluralsight-on-demand-is-now-live.aspx</id><published>2008-10-29T19:49:34Z</published><updated>2008-10-29T19:49:34Z</updated><content type="html">&lt;p&gt;I&amp;#39;ve been rather dark over the last couple of months as I helped to finish up &lt;a href="http://www.pluralsight.com" target="_blank"&gt;Pluralsight&amp;#39;s&lt;/a&gt; online training offering, &lt;a href="http://www.pluralsight.com/main/Default.aspx" target="_blank"&gt;Pluralsight On-Demand&lt;/a&gt;. I&amp;#39;m psyched that we finally shipped!&lt;/p&gt; &lt;p&gt;Be sure to check it out soon (you can preview bits of each course right now for free), as we&amp;#39;re offering a limited-time early adopter discount that&amp;#39;s good for the life of your subscription. Our online courses are told by the authors themselves, with names that you&amp;#39;ll recognize, as many are MSDN Magazine contributing editors and book authors on their topics.&lt;/p&gt; &lt;p&gt;Courses we now offer online include:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;a href="http://www.pluralsight.com/main/olt/Course.aspx?n=wcf-fundamentals"&gt;WCF Fundamentals&lt;/a&gt; by &lt;a href="http://www.pluralsight.com/main/instructor.aspx?name=aaron-skonnard"&gt;Aaron Skonnard&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.pluralsight.com/main/olt/Course.aspx?n=wf-fundamentals" target="_blank"&gt;Windows Workflow Fundamentals&lt;/a&gt;, by &lt;a href="http://www.pluralsight.com/main/instructor.aspx?name=matt-milner" target="_blank"&gt;Matt Milner&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.pluralsight.com/main/olt/Course.aspx?n=wpf-fundamentals"&gt;WPF Fundamentals&lt;/a&gt;, by &lt;a href="http://www.pluralsight.com/main/instructor.aspx?name=ian-griffiths"&gt;Ian Griffiths&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.pluralsight.com/main/olt/Course.aspx?n=silverlight-fundamentals"&gt;Silverlight Fundamentals&lt;/a&gt;, by &lt;a href="http://www.pluralsight.com/main/instructor.aspx?name=ian-griffiths"&gt;Ian Griffiths&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.pluralsight.com/main/olt/Course.aspx?n=aspdotnet-fundamentals" target="_blank"&gt;ASP.NET 3.5 Fundamentals&lt;/a&gt;, by &lt;a href="http://www.pluralsight.com/main/instructor.aspx?name=fritz-onion" target="_blank"&gt;Fritz Onion&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.pluralsight.com/main/olt/Course.aspx?n=aspdotnet-ajax-fundamentals" target="_blank"&gt;ASP.NET Ajax Fundamentals&lt;/a&gt;, by &lt;a href="http://www.pluralsight.com/main/instructor.aspx?name=fritz-onion" target="_blank"&gt;Fritz Onion&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.pluralsight.com/main/olt/Course.aspx?n=linq-fundamentals"&gt;LINQ Fundamentals&lt;/a&gt; by &lt;a href="http://www.pluralsight.com/main/instructor.aspx?name=scott-allen"&gt;Scott Allen&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.pluralsight.com/main/olt/Course.aspx?n=abts-fundamentals"&gt;BizTalk Fundamentals&lt;/a&gt; by &lt;a href="http://www.pluralsight.com/main/instructor.aspx?name=matt-milner" target="_blank"&gt;Matt Milner&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.pluralsight.com/main/olt/Course.aspx?n=btsr2-fundamentals"&gt;BizTalk Server 2006 R2 Fundamentals&lt;/a&gt; by &lt;a href="http://www.pluralsight.com/main/instructor.aspx?name=jon-flanders"&gt;Jon Flanders&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;We&amp;#39;ll be expanding this library of content in the months to come, as we continue to grow this online resource. I plan on adding modules on the &lt;a href="https://connect.microsoft.com/site/sitehome.aspx?SiteID=642&amp;amp;wa=wsignin1.0" target="_blank"&gt;Geneva&lt;/a&gt; family of identity products (Geneva Server, Geneva Framework, Geneva CardSpace) announced at PDC this week.&lt;/p&gt; &lt;p&gt;I&amp;#39;ve learned a lot of interesting tidbits as I helped to develop the back end infrastructure for Pluralsight On-Demand, and now that I&amp;#39;m not so crammed for time, I&amp;#39;ll be sharing those insights here on this blog.&lt;/p&gt; &lt;p&gt;Congrats to all who helped bring this incredible resource to the public!&lt;/p&gt; &lt;p&gt;Aaron &lt;a href="http://www.pluralsight.com/community/blogs/aaron/archive/2008/10/29/announcing-pluralsight-on-demand.aspx"&gt;has more details&lt;/a&gt; if you want to know about pricing, customer feedback, and so on.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.pluralsight.com/community/aggbug.aspx?PostID=54152" 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="ASP.NET" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/ASP.NET/default.aspx" /><category term="PowerShell" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/PowerShell/default.aspx" /><category term="GUI" scheme="http://www.pluralsight.com/community/blogs/keith/archive/tags/GUI/default.aspx" /></entry><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></feed>