<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><rss xmlns:blogChannel="http://backend.userland.com/blogChannelModule" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>Troy Goode: SquaredRoot</title>
    <description>ASP.Net, C#, MVC, and LINQ</description>
    <link>http://www.squaredroot.com/</link>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>BlogEngine.Net Syndication Generator 1.0.0.0 (http://dotnetblogengine.net/)</generator>
    <language>en-US</language>
    <blogChannel:blogRoll>http://www.squaredroot.com/opml.axd</blogChannel:blogRoll>
    <blogChannel:blink>http://www.dotnetblogengine.net/syndication.axd</blogChannel:blink>
    <dc:creator>Troy Goode</dc:creator>
    <dc:title>Troy Goode: SquaredRoot</dc:title>
    <geo:lat>38.880280</geo:lat>
    <geo:long>-77.109050</geo:long>
    <geo:lat>38.874979</geo:lat><geo:long>-77.114551</geo:long><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/Squaredroot" type="application/rss+xml" /><item>
      <title>MVC Membership Starter Kit - 1.2</title>
      <description>&lt;p&gt;This weekend I posted a &lt;a href="https://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=MvcMembership&amp;amp;ReleaseId=12667"&gt;new release of the MVC Membership Starter Kit&lt;/a&gt;. This release is an update to migrate the starter kit to &lt;a href="http://weblogs.asp.net/scottgu/archive/2008/04/16/asp-net-mvc-source-refresh-preview.aspx"&gt;the new interim release of the MVC framework&lt;/a&gt;. If you do not feel comfortable using the interim release, please continue using the 1.1 release and wait for Microsoft to release Preview 3; we will update the Starter Kit soon thereafter.&lt;/p&gt;  &lt;h3&gt;Changes in 1.2:&lt;/h3&gt;  &lt;ul&gt;   &lt;li&gt;WindowsLive is now a supported authentication scenario (&lt;a href="http://blog.maartenballiauw.be/post/2008/04/ASPNet-MVC-Membership-Starter-Kit-alternative-authentication.aspx"&gt;read Maarten's blog post on this&lt;/a&gt;). &lt;/li&gt;    &lt;li&gt;Per &lt;a href="http://blog.nerdbank.net/"&gt;Andrew Arnott's&lt;/a&gt; suggestion, the starter kit now uses the &lt;a href="http://code.google.com/p/dotnetopenid/"&gt;DotNetOpenId&lt;/a&gt; library rather than the code previously used (which was created by Mads Kristensen). This gives us a more robust and secure implementation that will develop and improve independently of this project.&lt;/li&gt;    &lt;li&gt;All actions that previously expected a username in the route now expect the user's ProviderUserKey (a Guid) instead. This was done because users with OpenID urls as their username could not previously be accessed. &lt;/li&gt;    &lt;li&gt;&amp;quot;Whitelist support&amp;quot; has been added to the OpenID implementation, allowing you to setup regular expressions that dictate which OpenID providers are allowed to be used when logging into your site. By default there is no whitelist, so all providers are allowed. &lt;/li&gt;    &lt;li&gt;The starter kit now offers greater control over which authentication scenarios your site supports and which is the default. Out-of-the-box only FormsAuthentication is enabled and is obviously the default. &lt;/li&gt; &lt;/ul&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/Squaredroot?a=uYeIvO"&gt;&lt;img src="http://feeds.feedburner.com/~a/Squaredroot?i=uYeIvO" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/Squaredroot?a=38gBrG"&gt;&lt;img src="http://feeds.feedburner.com/~f/Squaredroot?i=38gBrG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/Squaredroot?a=GpoOKg"&gt;&lt;img src="http://feeds.feedburner.com/~f/Squaredroot?i=GpoOKg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Squaredroot/~4/279639976" height="1" width="1"/&gt;</description>
      <link>http://feeds.feedburner.com/~r/Squaredroot/~3/279639976/post.aspx</link>
      <author>Troy Goode</author>
      <comments>http://www.squaredroot.com/post/2008/04/MVC-Membership-Starter-Kit-1-2.aspx#comment</comments>
      <guid isPermaLink="false">http://www.squaredroot.com/post.aspx?id=e6e0c22c-7043-4486-bce6-e5e279996e3f</guid>
      <pubDate>Mon, 28 Apr 2008 17:22:04 -0400</pubDate>
      <category>MVC</category>
      <dc:publisher>Troy Goode</dc:publisher>
      <pingback:server>http://www.squaredroot.com/pingback.axd</pingback:server>
      <pingback:target>http://www.squaredroot.com/post.aspx?id=e6e0c22c-7043-4486-bce6-e5e279996e3f</pingback:target>
      <slash:comments>6</slash:comments>
      <trackback:ping>http://www.squaredroot.com/trackback.axd?id=e6e0c22c-7043-4486-bce6-e5e279996e3f</trackback:ping>
      <wfw:comment>http://www.squaredroot.com/post/2008/04/MVC-Membership-Starter-Kit-1-2.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.squaredroot.com/syndication.axd?post=e6e0c22c-7043-4486-bce6-e5e279996e3f</wfw:commentRss>
    <feedburner:origLink>http://www.squaredroot.com/post.aspx?id=e6e0c22c-7043-4486-bce6-e5e279996e3f</feedburner:origLink></item>
    <item>
      <title>Massive BlogEngine.net Security Hole</title>
      <description>A massive security hole in BlogEngine.net was just revealed that allows anyone to see your passwords... Danny Douglass just added a post to his blog where he explains the issue and provides a patched BlogEngine.Core assembly to resolve the issue until the next release of BlogEngine is available. 
&lt;p&gt;
I would advise anyone running BlogEngine.net to immediately &lt;a href="http://dannydouglass.com/post/2008/04/BlogEngine-and-the-JavaScript-HttpHandler-Serious-Security-Issue.aspx"&gt;go to Danny&amp;#39;s blog and download &amp;amp; install the fix&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
The faster we can get word out about this, the faster we can shut down this particular attack vector, so please try and get the word out to any BlogEngine.net users you are aware of and please &lt;a href="http://www.dotnetkicks.com/security/Massive_BlogEngine_Net_Security_Hole_Fix_Provided"&gt;kick Danny&amp;#39;s post at DotNetKicks&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Thanks Danny!
&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/Squaredroot?a=AYP9cW"&gt;&lt;img src="http://feeds.feedburner.com/~a/Squaredroot?i=AYP9cW" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/Squaredroot?a=NITWEYG"&gt;&lt;img src="http://feeds.feedburner.com/~f/Squaredroot?i=NITWEYG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/Squaredroot?a=POkkXhg"&gt;&lt;img src="http://feeds.feedburner.com/~f/Squaredroot?i=POkkXhg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Squaredroot/~4/269739922" height="1" width="1"/&gt;</description>
      <link>http://feeds.feedburner.com/~r/Squaredroot/~3/269739922/post.aspx</link>
      <author>Troy Goode</author>
      <comments>http://www.squaredroot.com/post/2008/04/Massive-BlogEngineDotNet-Security-Hole.aspx#comment</comments>
      <guid isPermaLink="false">http://www.squaredroot.com/post.aspx?id=80a41ba3-2b31-4d7f-8d96-f87717ac8295</guid>
      <pubDate>Sun, 13 Apr 2008 22:34:00 -0400</pubDate>
      <category>Blogging</category>
      <dc:publisher>Troy Goode</dc:publisher>
      <pingback:server>http://www.squaredroot.com/pingback.axd</pingback:server>
      <pingback:target>http://www.squaredroot.com/post.aspx?id=80a41ba3-2b31-4d7f-8d96-f87717ac8295</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://www.squaredroot.com/trackback.axd?id=80a41ba3-2b31-4d7f-8d96-f87717ac8295</trackback:ping>
      <wfw:comment>http://www.squaredroot.com/post/2008/04/Massive-BlogEngineDotNet-Security-Hole.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.squaredroot.com/syndication.axd?post=80a41ba3-2b31-4d7f-8d96-f87717ac8295</wfw:commentRss>
    <feedburner:origLink>http://www.squaredroot.com/post.aspx?id=80a41ba3-2b31-4d7f-8d96-f87717ac8295</feedburner:origLink></item>
    <item>
      <title>MVC: New Membership Starter Kit Release</title>
      <description>&lt;h1&gt;The Starter Kit&lt;/h1&gt; &lt;p&gt;If you haven't had a chance to read about the MVC Membership Starter Kit I've created, &lt;a href="http://www.squaredroot.com/post/2008/04/MVC-Membership-Starter-Kit.aspx"&gt;read this post first&lt;/a&gt;.&lt;/p&gt; &lt;h1&gt;New Release&lt;/h1&gt; &lt;p&gt;Since we first created the starter kit a week and a half ago, &lt;a href="http://blog.maartenballiauw.be/"&gt;Maarten Balliauw&lt;/a&gt; and I have been hard at work fleshing out the implementation to provide as much functionality as possible. Last night we finished the last stretch of things we had identified for this release and have posted the code as a new release on CodePlex. Keep in mind you can also always download our latest builds from CodePlex as well without waiting for a new release.&lt;/p&gt; &lt;h1&gt;New Features&lt;/h1&gt; &lt;h2&gt;OpenID&lt;/h2&gt; &lt;p&gt;Mads Kristensen &lt;a href="http://blog.madskristensen.dk/post/OpenID-implementation-in-Csharp-and-ASPNET.aspx"&gt;released a lightweight OpenID consumer&lt;/a&gt; earlier this year that I then proceeded to flesh out with &lt;a href="http://www.squaredroot.com/post/2008/04/OpenID-Check_Authentication.aspx"&gt;a security patch&lt;/a&gt;. The reason I did so was so that I could include OpenID in this release of the Starter Kit.&lt;/p&gt; &lt;p&gt;Out of the box you can create a route to the OpenIDLogin action, which displays the following view:&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCNewMembershipStarterKitRelease_A490/OpenID_2.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="210" alt="OpenID" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCNewMembershipStarterKitRelease_A490/OpenID_thumb.jpg" width="204" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Once the user has entered their OpenID url, the starter kit will take care of the rest for you, with one critical exception: you have to map the url to a user in your membership database. To do so, you simple override a virtual method and return a MembershipUser, like so:&lt;/p&gt; &lt;div class="csharpcode-wrapper"&gt; &lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; MembershipUser AssociateOpenIDToMembershipUser( &lt;span class="kwrd"&gt;string&lt;/span&gt; identity, &lt;span class="kwrd"&gt;string&lt;/span&gt; name, &lt;span class="kwrd"&gt;string&lt;/span&gt; email )&lt;/pre&gt;&lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt;     &lt;span class="kwrd"&gt;return&lt;/span&gt; Membership.GetUser(identity);&lt;/pre&gt;&lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="CopyToClipboard" style=""&gt;&lt;div&gt;&lt;a href="javascript:void(0);" onclick="CopyToClipboard_ViewPlain(copyToClipboard1370b95304b447cdb0388f6bdbfaefc7_1980);"&gt;View Plain&lt;/a&gt; | &lt;a href="javascript:void(0);" onclick="CopyToClipboard_Copy(copyToClipboard1370b95304b447cdb0388f6bdbfaefc7_1980);"&gt;Copy To Clipboard&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
				&lt;div id="CopyToClipboard_Hidden" style="display:none;"&gt;&lt;/div&gt;
				&lt;div id="CopyToClipboard_FlashContainer"&gt;&lt;/div&gt;
                &lt;script type="text/javascript"&gt;

					function CopyToClipboard_Strip( text ){
						text = text.replace( /&amp;nbsp;/g, ' ' );
						text = text.replace( /&amp;quot;/g, '"' );
						text = text.replace( /&amp;#39;/g, '"' );
						text = text.replace( /&amp;amp;/g, '&amp;' );
						text = text.replace( /&amp;lt;/g, String.fromCharCode(60) );
						text = text.replace( /&amp;gt;/g, String.fromCharCode(62) );
						return text;
					}

                    function CopyToClipboard_Copy( text ){

						//### get reference to utility div
						var ele = document.getElementById('CopyToClipboard_Hidden');

						//### the following taken from: http://webchicanery.com/2006/11/14/clipboard-copy-javascript/
						if (false &amp;&amp; window.clipboardData) {
							window.clipboardData.setData( "Text", text );
						} else {
							document.getElementById('CopyToClipboard_FlashContainer').innerHTML = '';
							var divinfo = '&lt;embed id="CopyToClipboard_FlashFile" src="/themes/Naturalist/_clipboard.swf" FlashVars="clipboard=' + encodeURIComponent(text) + '" width="0" height="0" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;';
							document.getElementById('CopyToClipboard_FlashContainer').innerHTML = divinfo;
						}

                    }

					function CopyToClipboard_ViewPlain( text ){
						var win = window.open( '', 'CopyToClipboard_Window', 'width=480, height=480, toolbar=no, menubar=no, scrollbars=auto, resizable=yes, location=no, directories=no, status=no' );
						win.document.write( '&lt;html&gt;&lt;head&gt;&lt;title&gt;Code&lt;/title&gt;&lt;body style="margin:0;padding:0;"&gt;&lt;textarea style="width:100%;height:100%;border:0;"&gt;' + text + '&lt;/textarea&gt;&lt;/body&gt;&lt;/html&gt;' );
					}

                &lt;/script&gt;
            
					&lt;script type="text/javascript"&gt;
						var copyToClipboard1370b95304b447cdb0388f6bdbfaefc7_1980 = CopyToClipboard_Strip('protected override MembershipUser AssociateOpenIDToMembershipUser( string identity, string name, string email )   2: {   3:     return Membership.GetUser(identity);   4: }');
					&lt;/script&gt;
&lt;p&gt;Note that the above implementation maps the OpenID url to a user's UserName, which may or may not be what you want for your application. Adjust accordingly.&lt;/p&gt;
&lt;h2&gt;Password Recovery Tools&lt;/h2&gt;
&lt;p&gt;Maarten did a great job providing users with a way to manage their passwords. While logged in they can change their password:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCNewMembershipStarterKitRelease_A490/ChangePassword_2.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="240" alt="ChangePassword" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCNewMembershipStarterKitRelease_A490/ChangePassword_thumb.jpg" width="167" border="0"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Or if they are having trouble logging in, they can submit their username...&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCNewMembershipStarterKitRelease_A490/ForgotPassword_2.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="184" alt="ForgotPassword" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCNewMembershipStarterKitRelease_A490/ForgotPassword_thumb.jpg" width="240" border="0"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;...and then answer their password question (if the system is configured to require it)...&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCNewMembershipStarterKitRelease_A490/PasswordQuestion_2.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="177" alt="PasswordQuestion" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCNewMembershipStarterKitRelease_A490/PasswordQuestion_thumb.jpg" width="240" border="0"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;...and they will then receive their password via email (or a newly generated password -- depending on system configuration).&lt;/p&gt;
&lt;h2&gt;Client-Side Validation&lt;/h2&gt;
&lt;p&gt;All non-administrative forms now include basic client-side validation. The validations even change based upon your Membership settings.&lt;/p&gt;
&lt;p&gt;For instance, by default the ASP.Net Membership provider requires passwords to contain at least 1 non-alphanumeric character. If a user entered a password of "password" they would see the following alert:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCNewMembershipStarterKitRelease_A490/ClientSideValidation_2.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="149" alt="ClientSideValidation" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCNewMembershipStarterKitRelease_A490/ClientSideValidation_thumb.jpg" width="443" border="0"&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Components: Login &amp;amp; LoginStatus&lt;/h2&gt;
&lt;p&gt;Maarten created components that emulate the functionality of the old Login and LoginStatus controls. Now it is easy to have a Login box on every page.&lt;/p&gt;
&lt;h2&gt;Major Refactoring&lt;/h2&gt;
&lt;p&gt;Most of the controller and filter code has been broken out into a separate assembly.&lt;/p&gt;
&lt;p&gt;Your FormsAuthentication and FormsAuthenticationAdministration controllers should now inherit from a base version of each. Maarten has created a boat load of virtual method hooks for each action (OnBeforeBlah, OnAfterBlah, OnErrorBlah) that provides you with easy extensibility points without needing to directly modify the starter kit base code.&lt;/p&gt;
&lt;p&gt;Hopefully this refactoring will make it easy for you to upgrade to future versions of the starter kit's code as they become available.&lt;/p&gt;
&lt;h1&gt;The Future&lt;/h1&gt;
&lt;p&gt;Currently we've cleared our plate and have no more planned features to attend to. Does this mean that we are done? No. This is what you can expect to see us working on next:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Preview3 updates, whenever it becomes available.&lt;/li&gt;
&lt;li&gt;Validations on the administrative side.&lt;/li&gt;
&lt;li&gt;Bug fixes, of course. :-)&lt;/li&gt;
&lt;li&gt;If you have suggestions for what you would like to see in the next release, please &lt;a href="http://www.squaredroot.com/page/About-Me.aspx#ContactInformation"&gt;drop me a line&lt;/a&gt; and let me know!&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;You can &lt;a href="https://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=MvcMembership&amp;amp;ReleaseId=12261"&gt;download the new release&lt;/a&gt; from CodePlex.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/Squaredroot?a=NjXe3G"&gt;&lt;img src="http://feeds.feedburner.com/~a/Squaredroot?i=NjXe3G" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/Squaredroot?a=ePDXdOG"&gt;&lt;img src="http://feeds.feedburner.com/~f/Squaredroot?i=ePDXdOG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/Squaredroot?a=EH9TO9g"&gt;&lt;img src="http://feeds.feedburner.com/~f/Squaredroot?i=EH9TO9g" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Squaredroot/~4/268463751" height="1" width="1"/&gt;</description>
      <link>http://feeds.feedburner.com/~r/Squaredroot/~3/268463751/post.aspx</link>
      <author>Troy Goode</author>
      <comments>http://www.squaredroot.com/post/2008/04/MVC-Membership-Starter-Kit-11.aspx#comment</comments>
      <guid isPermaLink="false">http://www.squaredroot.com/post.aspx?id=5c6f6109-8d52-4cb8-9fd7-981fe5d459ce</guid>
      <pubDate>Fri, 11 Apr 2008 12:19:21 -0400</pubDate>
      <category>MVC</category>
      <dc:publisher>Troy Goode</dc:publisher>
      <pingback:server>http://www.squaredroot.com/pingback.axd</pingback:server>
      <pingback:target>http://www.squaredroot.com/post.aspx?id=5c6f6109-8d52-4cb8-9fd7-981fe5d459ce</pingback:target>
      <slash:comments>9</slash:comments>
      <trackback:ping>http://www.squaredroot.com/trackback.axd?id=5c6f6109-8d52-4cb8-9fd7-981fe5d459ce</trackback:ping>
      <wfw:comment>http://www.squaredroot.com/post/2008/04/MVC-Membership-Starter-Kit-11.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.squaredroot.com/syndication.axd?post=5c6f6109-8d52-4cb8-9fd7-981fe5d459ce</wfw:commentRss>
    <feedburner:origLink>http://www.squaredroot.com/post.aspx?id=5c6f6109-8d52-4cb8-9fd7-981fe5d459ce</feedburner:origLink></item>
    <item>
      <title>OpenID Check_Authentication In C#</title>
      <description>&lt;p&gt;Earlier this year Mads Krisensen (of &lt;a href="http://www.dotnetblogengine.net/"&gt;BlogEngine.net&lt;/a&gt; fame) posted a &lt;a href="http://blog.madskristensen.dk/post/OpenID-implementation-in-Csharp-and-ASPNET.aspx"&gt;lightweight implementation of OpenID&lt;/a&gt; using C#. In the comments on Mads' post, &lt;a href="http://blog.nerdbank.net/"&gt;Andrew Arnott&lt;/a&gt; (&lt;a href="http://blog.nerdbank.net/2008/04/dotnetopenid-2.html"&gt;a developer of the DotNetOpenId library&lt;/a&gt;) mentioned that the example Mads had posted could &amp;quot;be hacked with a single change of a word in the URL.&amp;quot; This is what is technically referred to as a &lt;strong&gt;Very Bad Thing&lt;/strong&gt;. Andrew and another poster named &amp;quot;neil&amp;quot; went on to elaborate that implementing OpenID's &amp;quot;check_authentication&amp;quot; algorithm would close this security hole. Unfortunately as of the writing of this article neither Mads nor any of the commentors have provided an implementation of check_authentication that works with the class Mads posted (bear in mind that Andrew only brought up this issue less than a week ago, so Mads may very well be working on it).&lt;/p&gt;  &lt;p&gt;Fast forward to yesterday when I was researching my options for implementing OpenID for the next release of the &lt;a href="http://www.codeplex.com/MvcMembership"&gt;ASP.Net MVC Membership Starter Kit&lt;/a&gt;. I liked Mads solution more than the other OpenID libraries that are current available because of its brevity and how easy it is to include it in a project without introducing an extra assembly dependency, so I decided to go ahead and add the check_authentication functionality. A quick read of &lt;a href="http://openid.net/specs/openid-authentication-1_1.html#mode_check_authentication"&gt;that portion of the OpenID spec&lt;/a&gt; and a couple hours of coding/testing and I think I'm about finished.&lt;/p&gt;  &lt;p&gt;Here is the method you need to add to Mads' class:&lt;/p&gt;  &lt;div class="csharpcode-wrapper"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:&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;bool&lt;/span&gt; CheckAuthentication( NameValueCollection query )&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt;     &lt;span class="rem"&gt;//### get data required for check_authentication&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:&lt;/span&gt;     &lt;span class="kwrd"&gt;string&lt;/span&gt; mode = &lt;span class="str"&gt;&amp;quot;check_authentication&amp;quot;&lt;/span&gt;;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   6:&lt;/span&gt;     &lt;span class="kwrd"&gt;string&lt;/span&gt; handle = query[&lt;span class="str"&gt;&amp;quot;openid.assoc_handle&amp;quot;&lt;/span&gt;];&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:&lt;/span&gt;     &lt;span class="kwrd"&gt;string&lt;/span&gt; signature = query[&lt;span class="str"&gt;&amp;quot;openid.sig&amp;quot;&lt;/span&gt;];&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   8:&lt;/span&gt;     &lt;span class="kwrd"&gt;string&lt;/span&gt; signed = query[&lt;span class="str"&gt;&amp;quot;openid.signed&amp;quot;&lt;/span&gt;];&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:&lt;/span&gt;     &lt;span class="kwrd"&gt;string&lt;/span&gt; extra = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  10:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:&lt;/span&gt;     &lt;span class="rem"&gt;//### loop through fields required by &amp;quot;openid.signed&amp;quot; and retrieve that data&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  12:&lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt;( !&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(signed) )&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  14:&lt;/span&gt;         &lt;span class="kwrd"&gt;string&lt;/span&gt;[] exemptions = { &lt;span class="str"&gt;&amp;quot;mode&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;assoc_handle&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;sig&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;signed&amp;quot;&lt;/span&gt; };&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:&lt;/span&gt;         &lt;span class="kwrd"&gt;string&lt;/span&gt;[] fields = signed.Split(&lt;span class="str"&gt;','&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  16:&lt;/span&gt;         &lt;span class="kwrd"&gt;foreach&lt;/span&gt;( &lt;span class="kwrd"&gt;string&lt;/span&gt; field &lt;span class="kwrd"&gt;in&lt;/span&gt; fields )&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:&lt;/span&gt;         {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  18:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;( exemptions.Contains(field) ) &lt;span class="kwrd"&gt;continue&lt;/span&gt;;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:&lt;/span&gt;             extra += &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format( &lt;span class="str"&gt;&amp;quot;openid.{0}={1}&amp;amp;&amp;quot;&lt;/span&gt;, field, HttpUtility.UrlEncode( query[ &lt;span class="str"&gt;&amp;quot;openid.&amp;quot;&lt;/span&gt; + field ] ) );&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  20:&lt;/span&gt;         }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:&lt;/span&gt;         extra = &lt;span class="str"&gt;&amp;quot;&amp;amp;&amp;quot;&lt;/span&gt; + extra.Substring( 0, extra.Length - 1 );&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  22:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  24:&lt;/span&gt;     &lt;span class="rem"&gt;//### combine all the data together to form the request&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:&lt;/span&gt;     &lt;span class="kwrd"&gt;string&lt;/span&gt; post = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format( &lt;span class="str"&gt;&amp;quot;openid.mode={0}&amp;amp;openid.assoc_handle={1}&amp;amp;openid.sig={2}&amp;amp;openid.signed={3}{4}&amp;quot;&lt;/span&gt;,&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  26:&lt;/span&gt;         mode,&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:&lt;/span&gt;         HttpUtility.UrlEncode( handle ),&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  28:&lt;/span&gt;         HttpUtility.UrlEncode( signature ),&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:&lt;/span&gt;         HttpUtility.UrlEncode( signed ),&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  30:&lt;/span&gt;         extra&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:&lt;/span&gt;     );&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  32:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:&lt;/span&gt;     &lt;span class="rem"&gt;//### begin sending request&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  34:&lt;/span&gt;     HttpWebRequest request = (HttpWebRequest)WebRequest.Create( query[&lt;span class="str"&gt;&amp;quot;openid.op_endpoint&amp;quot;&lt;/span&gt;] );&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:&lt;/span&gt;     request.Method = &lt;span class="str"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  36:&lt;/span&gt;     request.ContentType = &lt;span class="str"&gt;&amp;quot;application/x-www-form-urlencoded&amp;quot;&lt;/span&gt;;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:&lt;/span&gt;     request.ContentLength = post.Length;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  38:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:&lt;/span&gt;     &lt;span class="rem"&gt;//### transmit POST data&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  40:&lt;/span&gt;     &lt;span class="kwrd"&gt;using&lt;/span&gt;( StreamWriter sw = &lt;span class="kwrd"&gt;new&lt;/span&gt; StreamWriter(request.GetRequestStream()) )&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:&lt;/span&gt;         sw.Write(post);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  42:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:&lt;/span&gt;     &lt;span class="rem"&gt;//### get response&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  44:&lt;/span&gt;     &lt;span class="kwrd"&gt;string&lt;/span&gt; html = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:&lt;/span&gt;     &lt;span class="kwrd"&gt;using&lt;/span&gt;( HttpWebResponse response = (HttpWebResponse)request.GetResponse() )&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  46:&lt;/span&gt;         &lt;span class="kwrd"&gt;using&lt;/span&gt;( StreamReader sr = &lt;span class="kwrd"&gt;new&lt;/span&gt; StreamReader( response.GetResponseStream() ) )&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  47:&lt;/span&gt;             html = sr.ReadToEnd();&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  48:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  49:&lt;/span&gt;     &lt;span class="rem"&gt;//### determine if check_authentication passed or not&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  50:&lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt;( &lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(html) || !html.StartsWith( &lt;span class="str"&gt;&amp;quot;is_valid:&amp;quot;&lt;/span&gt; ) || html.StartsWith( &lt;span class="str"&gt;&amp;quot;is_valid:false&amp;quot;&lt;/span&gt; ) )&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  51:&lt;/span&gt;         &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  52:&lt;/span&gt;     &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;( html.StartsWith( &lt;span class="str"&gt;&amp;quot;is_valid:true&amp;quot;&lt;/span&gt; ) )&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  53:&lt;/span&gt;         &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  54:&lt;/span&gt;     &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  55:&lt;/span&gt;         &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidOperationException( &lt;span class="str"&gt;&amp;quot;Unexpected return from OpenID check_authentication.&amp;quot;&lt;/span&gt; );&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  56:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  57:&lt;/span&gt; }&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;&lt;div class="CopyToClipboard" style=""&gt;&lt;div&gt;&lt;a href="javascript:void(0);" onclick="CopyToClipboard_ViewPlain(copyToClipboard54ad757ba4724e8eb4d236762567cc60_1878);"&gt;View Plain&lt;/a&gt; | &lt;a href="javascript:void(0);" onclick="CopyToClipboard_Copy(copyToClipboard54ad757ba4724e8eb4d236762567cc60_1878);"&gt;Copy To Clipboard&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
					&lt;script type="text/javascript"&gt;
						var copyToClipboard54ad757ba4724e8eb4d236762567cc60_1878 = CopyToClipboard_Strip('private static bool CheckAuthentication( NameValueCollection query )\r\n{\r\n\r\n    //### get data required for check_authentication\r\n    string mode = &amp;quot;check_authentication&amp;quot;;\r\n    string handle = query[&amp;quot;openid.assoc_handle&amp;quot;];\r\n    string signature = query[&amp;quot;openid.sig&amp;quot;];\r\n    string signed = query[&amp;quot;openid.signed&amp;quot;];\r\n    string extra = string.Empty;\r\n\r\n    //### loop through fields required by &amp;quot;openid.signed&amp;quot; and retrieve that data\r\n    if( !string.IsNullOrEmpty(signed) )\r\n    {\r\n        string[] exemptions = { &amp;quot;mode&amp;quot;, &amp;quot;assoc_handle&amp;quot;, &amp;quot;sig&amp;quot;, &amp;quot;signed&amp;quot; };\r\n        string[] fields = signed.Split(\',\');\r\n        foreach( string field in fields )\r\n        {\r\n            if( exemptions.Contains(field) ) continue;\r\n            extra += string.Format( &amp;quot;openid.{0}={1}&amp;amp;&amp;quot;, field, HttpUtility.UrlEncode( query[ &amp;quot;openid.&amp;quot; + field ] ) );\r\n        }\r\n        extra = &amp;quot;&amp;amp;&amp;quot; + extra.Substring( 0, extra.Length - 1 );\r\n    }\r\n\r\n    //### combine all the data together to form the request\r\n    string post = string.Format( &amp;quot;openid.mode={0}&amp;amp;openid.assoc_handle={1}&amp;amp;openid.sig={2}&amp;amp;openid.signed={3}{4}&amp;quot;,\r\n        mode,\r\n        HttpUtility.UrlEncode( handle ),\r\n        HttpUtility.UrlEncode( signature ),\r\n        HttpUtility.UrlEncode( signed ),\r\n        extra\r\n    );\r\n\r\n    //### begin sending request\r\n    HttpWebRequest request = (HttpWebRequest)WebRequest.Create( query[&amp;quot;openid.op_endpoint&amp;quot;] );\r\n    request.Method = &amp;quot;POST&amp;quot;;\r\n    request.ContentType = &amp;quot;application/x-www-form-urlencoded&amp;quot;;\r\n    request.ContentLength = post.Length;\r\n\r\n    //### transmit POST data\r\n    using( StreamWriter sw = new StreamWriter(request.GetRequestStream()) )\r\n        sw.Write(post);\r\n\r\n    //### get response\r\n    string html = &amp;quot;&amp;quot;;\r\n    using( HttpWebResponse response = (HttpWebResponse)request.GetResponse() )\r\n        using( StreamReader sr = new StreamReader( response.GetResponseStream() ) )\r\n            html = sr.ReadToEnd();\r\n\r\n    //### determine if check_authentication passed or not\r\n    if( string.IsNullOrEmpty(html) || !html.StartsWith( &amp;quot;is_valid:&amp;quot; ) || html.StartsWith( &amp;quot;is_valid:false&amp;quot; ) )\r\n        return false;\r\n    else if( html.StartsWith( &amp;quot;is_valid:true&amp;quot; ) )\r\n        return true;\r\n    else\r\n        throw new InvalidOperationException( &amp;quot;Unexpected return from OpenID check_authentication.&amp;quot; );\r\n\r\n}');
					&lt;/script&gt;

&lt;p&gt;Now you need to make sure that method is called from somewhere. I chose to make the method private and just call it from inside the Authenticate method. Within the Authenticate method replace:&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="rem"&gt;// Make sure the incoming request's identity matches the one stored in session&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;( query[&lt;span class="str"&gt;&amp;quot;openid.claimed_id&amp;quot;&lt;/span&gt;] != data.Identity )&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt;     &lt;span class="kwrd"&gt;return&lt;/span&gt; data;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;&lt;div class="CopyToClipboard" style=""&gt;&lt;div&gt;&lt;a href="javascript:void(0);" onclick="CopyToClipboard_ViewPlain(copyToClipboard54ad757ba4724e8eb4d236762567cc60_13115);"&gt;View Plain&lt;/a&gt; | &lt;a href="javascript:void(0);" onclick="CopyToClipboard_Copy(copyToClipboard54ad757ba4724e8eb4d236762567cc60_13115);"&gt;Copy To Clipboard&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
					&lt;script type="text/javascript"&gt;
						var copyToClipboard54ad757ba4724e8eb4d236762567cc60_13115 = CopyToClipboard_Strip('// Make sure the incoming request\'s identity matches the one stored in session\r\nif( query[&amp;quot;openid.claimed_id&amp;quot;] != data.Identity )\r\n    return data;');
					&lt;/script&gt;

&lt;p&gt;... with...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="rem"&gt;// Make sure the incoming request's identity matches the one stored in session&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;( query[&lt;span class="str"&gt;&amp;quot;openid.claimed_id&amp;quot;&lt;/span&gt;] != data.Identity )&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt;     &lt;span class="kwrd"&gt;return&lt;/span&gt; data;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt; &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;( !CheckAuthentication( query ) )&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:&lt;/span&gt;     &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; UnauthorizedAccessException( &lt;span class="str"&gt;&amp;quot;OpenID False Verification Detected&amp;quot;&lt;/span&gt; );&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;&lt;div class="CopyToClipboard" style=""&gt;&lt;div&gt;&lt;a href="javascript:void(0);" onclick="CopyToClipboard_ViewPlain(copyToClipboard54ad757ba4724e8eb4d236762567cc60_14307);"&gt;View Plain&lt;/a&gt; | &lt;a href="javascript:void(0);" onclick="CopyToClipboard_Copy(copyToClipboard54ad757ba4724e8eb4d236762567cc60_14307);"&gt;Copy To Clipboard&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
					&lt;script type="text/javascript"&gt;
						var copyToClipboard54ad757ba4724e8eb4d236762567cc60_14307 = CopyToClipboard_Strip('// Make sure the incoming request\'s identity matches the one stored in session\r\nif( query[&amp;quot;openid.claimed_id&amp;quot;] != data.Identity )\r\n    return data;\r\nelse if( !CheckAuthentication( query ) )\r\n    throw new UnauthorizedAccessException( &amp;quot;OpenID False Verification Detected&amp;quot; );');
					&lt;/script&gt;

&lt;p&gt;And that's it!&lt;/p&gt;

&lt;p&gt;If anyone with more experience than I in OpenID waters sees a problem with my implementation, let me know and I will try to get it fixed quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I am aware that Mads' implementation and the use of 'check_authentication' is considered an overly chatty use of OpenID. It seems to me that the extra complexity required to implement OpenID 2.0 protocol is just not worthwhile for most OpenID consumers. Feel free to let me know why this is a stupid position to take.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/Squaredroot?a=UmJALe"&gt;&lt;img src="http://feeds.feedburner.com/~a/Squaredroot?i=UmJALe" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/Squaredroot?a=WuDUsLG"&gt;&lt;img src="http://feeds.feedburner.com/~f/Squaredroot?i=WuDUsLG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/Squaredroot?a=Z1whueg"&gt;&lt;img src="http://feeds.feedburner.com/~f/Squaredroot?i=Z1whueg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Squaredroot/~4/268121939" height="1" width="1"/&gt;</description>
      <link>http://feeds.feedburner.com/~r/Squaredroot/~3/268121939/post.aspx</link>
      <author>Troy Goode</author>
      <comments>http://www.squaredroot.com/post/2008/04/OpenID-Check_Authentication.aspx#comment</comments>
      <guid isPermaLink="false">http://www.squaredroot.com/post.aspx?id=54586c73-02a1-435b-9fcb-4609d5c4b01e</guid>
      <pubDate>Fri, 11 Apr 2008 00:01:03 -0400</pubDate>
      <category>C#</category>
      <dc:publisher>Troy Goode</dc:publisher>
      <pingback:server>http://www.squaredroot.com/pingback.axd</pingback:server>
      <pingback:target>http://www.squaredroot.com/post.aspx?id=54586c73-02a1-435b-9fcb-4609d5c4b01e</pingback:target>
      <slash:comments>11</slash:comments>
      <trackback:ping>http://www.squaredroot.com/trackback.axd?id=54586c73-02a1-435b-9fcb-4609d5c4b01e</trackback:ping>
      <wfw:comment>http://www.squaredroot.com/post/2008/04/OpenID-Check_Authentication.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.squaredroot.com/syndication.axd?post=54586c73-02a1-435b-9fcb-4609d5c4b01e</wfw:commentRss>
    <feedburner:origLink>http://www.squaredroot.com/post.aspx?id=54586c73-02a1-435b-9fcb-4609d5c4b01e</feedburner:origLink></item>
    <item>
      <title>Rob Conery's PagedList Class (Updated)</title>
      <description>&lt;p&gt;Robert Muehsig has posted a great user control for the MVC framework that &lt;a href="http://code-inside.de/blog-in/2008/04/08/aspnet-mvc-pagination-view-user-control/"&gt;adds pagination links to the bottom of a paged list&lt;/a&gt;. In it he used a slightly customized version of &lt;a href="http://blog.wekeroad.com/2007/12/10/aspnet-mvc-pagedlistt/"&gt;Rob Conery's PagedList&lt;/a&gt; class that Rob was kind enough to post way back when the first CTP was released. This reminded me that I should probably post the version I have customized, as I think it makes it a bit easier to use and maintain. I've included the code below.&lt;/p&gt;  &lt;div class="csharpcode-wrapper"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt; &lt;span class="kwrd"&gt;namespace&lt;/span&gt; System.Collections.Generic&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   6:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IPagedList&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   8:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:&lt;/span&gt;         &lt;span class="kwrd"&gt;int&lt;/span&gt; TotalPages { get; }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  10:&lt;/span&gt;         &lt;span class="kwrd"&gt;int&lt;/span&gt; TotalCount { get; }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:&lt;/span&gt;         &lt;span class="kwrd"&gt;int&lt;/span&gt; PageIndex { get; }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  12:&lt;/span&gt;         &lt;span class="kwrd"&gt;int&lt;/span&gt; PageSize { get; }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:&lt;/span&gt;         &lt;span class="kwrd"&gt;bool&lt;/span&gt; HasPreviousPage { get; }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  14:&lt;/span&gt;         &lt;span class="kwrd"&gt;bool&lt;/span&gt; HasNextPage { get; }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:&lt;/span&gt;         &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsFirstPage { get; }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  16:&lt;/span&gt;         &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsLastPage { get; }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  18:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; PagedList&amp;lt;T&amp;gt; : List&amp;lt;T&amp;gt;, IPagedList&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  20:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  22:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; PagedList( IEnumerable&amp;lt;T&amp;gt; source, &lt;span class="kwrd"&gt;int&lt;/span&gt; index, &lt;span class="kwrd"&gt;int&lt;/span&gt; pageSize )&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:&lt;/span&gt;         {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  24:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:&lt;/span&gt;             &lt;span class="rem"&gt;//### set source to blank list if source is null to prevent exceptions&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  26:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;( source == &lt;span class="kwrd"&gt;null&lt;/span&gt; )&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:&lt;/span&gt;                 source = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;T&amp;gt;();&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  28:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:&lt;/span&gt;             &lt;span class="rem"&gt;//### set properties&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  30:&lt;/span&gt;             &lt;span class="kwrd"&gt;this&lt;/span&gt;.TotalCount = source.Count();&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:&lt;/span&gt;             &lt;span class="kwrd"&gt;this&lt;/span&gt;.PageSize = pageSize;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  32:&lt;/span&gt;             &lt;span class="kwrd"&gt;this&lt;/span&gt;.PageIndex = index;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;( &lt;span class="kwrd"&gt;this&lt;/span&gt;.TotalCount &amp;gt; 0 )&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  34:&lt;/span&gt;                 &lt;span class="kwrd"&gt;this&lt;/span&gt;.TotalPages = (&lt;span class="kwrd"&gt;int&lt;/span&gt;)Math.Ceiling( (&lt;span class="kwrd"&gt;double&lt;/span&gt;)&lt;span class="kwrd"&gt;this&lt;/span&gt;.TotalCount / (&lt;span class="kwrd"&gt;double&lt;/span&gt;)&lt;span class="kwrd"&gt;this&lt;/span&gt;.PageSize );&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:&lt;/span&gt;             &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  36:&lt;/span&gt;                 &lt;span class="kwrd"&gt;this&lt;/span&gt;.TotalPages = 0;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:&lt;/span&gt;             &lt;span class="kwrd"&gt;this&lt;/span&gt;.HasPreviousPage = ( &lt;span class="kwrd"&gt;this&lt;/span&gt;.PageIndex &amp;gt; 1 );&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  38:&lt;/span&gt;             &lt;span class="kwrd"&gt;this&lt;/span&gt;.HasNextPage = ( &lt;span class="kwrd"&gt;this&lt;/span&gt;.PageIndex &amp;lt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.TotalPages );&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:&lt;/span&gt;             &lt;span class="kwrd"&gt;this&lt;/span&gt;.IsFirstPage = ( &lt;span class="kwrd"&gt;this&lt;/span&gt;.PageIndex == 1 );&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  40:&lt;/span&gt;             &lt;span class="kwrd"&gt;this&lt;/span&gt;.IsLastPage = ( &lt;span class="kwrd"&gt;this&lt;/span&gt;.PageIndex == &lt;span class="kwrd"&gt;this&lt;/span&gt;.TotalPages );&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  42:&lt;/span&gt;             &lt;span class="rem"&gt;//### argument checking&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;( index &amp;lt; 1 || index &amp;gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.TotalPages )&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  44:&lt;/span&gt;                 &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentOutOfRangeException( &lt;span class="str"&gt;&amp;quot;PageIndex out of range.&amp;quot;&lt;/span&gt; );&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;( pageSize &amp;lt; 1 )&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  46:&lt;/span&gt;                 &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentOutOfRangeException( &lt;span class="str"&gt;&amp;quot;PageSize cannot be less than 1.&amp;quot;&lt;/span&gt; );&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  47:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  48:&lt;/span&gt;             &lt;span class="rem"&gt;//### add items to internal list&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  49:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;( &lt;span class="kwrd"&gt;this&lt;/span&gt;.TotalCount &amp;gt; 0 )&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  50:&lt;/span&gt;                 &lt;span class="kwrd"&gt;this&lt;/span&gt;.AddRange( source.Skip( ( index - 1 ) * pageSize ).Take( pageSize ).ToList() );&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  51:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  52:&lt;/span&gt;         }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  53:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  54:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; TotalPages { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  55:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; TotalCount { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  56:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; PageIndex { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  57:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; PageSize { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  58:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; HasPreviousPage { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  59:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; HasNextPage { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  60:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsFirstPage { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  61:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsLastPage { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  62:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  63:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  64:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  65:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Pagination&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  66:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  67:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; PagedList&amp;lt;T&amp;gt; ToPagedList&amp;lt;T&amp;gt;( &lt;span class="kwrd"&gt;this&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; source, &lt;span class="kwrd"&gt;int&lt;/span&gt; index, &lt;span class="kwrd"&gt;int&lt;/span&gt; pageSize )&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  68:&lt;/span&gt;         {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  69:&lt;/span&gt;             &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; PagedList&amp;lt;T&amp;gt;( source, index, pageSize );&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  70:&lt;/span&gt;         }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  71:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  72:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  73:&lt;/span&gt; }&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;&lt;div class="CopyToClipboard" style=""&gt;&lt;div&gt;&lt;a href="javascript:void(0);" onclick="CopyToClipboard_ViewPlain(copyToClipboard28d60026f278462e9aff8e69c2a8781f_618);"&gt;View Plain&lt;/a&gt; | &lt;a href="javascript:void(0);" onclick="CopyToClipboard_Copy(copyToClipboard28d60026f278462e9aff8e69c2a8781f_618);"&gt;Copy To Clipboard&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
					&lt;script type="text/javascript"&gt;
						var copyToClipboard28d60026f278462e9aff8e69c2a8781f_618 = CopyToClipboard_Strip('using System;\r\nusing System.Linq;\r\n\r\nnamespace System.Collections.Generic\r\n{\r\n\r\n    public interface IPagedList\r\n    {\r\n        int TotalPages { get; }\r\n        int TotalCount { get; }\r\n        int PageIndex { get; }\r\n        int PageSize { get; }\r\n        bool HasPreviousPage { get; }\r\n        bool HasNextPage { get; }\r\n        bool IsFirstPage { get; }\r\n        bool IsLastPage { get; }\r\n    }\r\n\r\n    public class PagedList&amp;lt;T&amp;gt; : List&amp;lt;T&amp;gt;, IPagedList\r\n    {\r\n\r\n        public PagedList( IEnumerable&amp;lt;T&amp;gt; source, int index, int pageSize )\r\n        {\r\n\r\n            //### set source to blank list if source is null to prevent exceptions\r\n            if( source == null )\r\n                source = new List&amp;lt;T&amp;gt;();\r\n\r\n            //### set properties\r\n            this.TotalCount = source.Count();\r\n            this.PageSize = pageSize;\r\n            this.PageIndex = index;\r\n            if( this.TotalCount &amp;gt; 0 )\r\n                this.TotalPages = (int)Math.Ceiling( (double)this.TotalCount / (double)this.PageSize );\r\n            else\r\n                this.TotalPages = 0;\r\n            this.HasPreviousPage = ( this.PageIndex &amp;gt; 1 );\r\n            this.HasNextPage = ( this.PageIndex &amp;lt; this.TotalPages );\r\n            this.IsFirstPage = ( this.PageIndex == 1 );\r\n            this.IsLastPage = ( this.PageIndex == this.TotalPages );\r\n\r\n            //### argument checking\r\n            if( index &amp;lt; 1 || index &amp;gt; this.TotalPages )\r\n                throw new ArgumentOutOfRangeException( &amp;quot;PageIndex out of range.&amp;quot; );\r\n            if( pageSize &amp;lt; 1 )\r\n                throw new ArgumentOutOfRangeException( &amp;quot;PageSize cannot be less than 1.&amp;quot; );\r\n\r\n            //### add items to internal list\r\n            if( this.TotalCount &amp;gt; 0 )\r\n                this.AddRange( source.Skip( ( index - 1 ) * pageSize ).Take( pageSize ).ToList() );\r\n\r\n        }\r\n\r\n        public int TotalPages { get; private set; }\r\n        public int TotalCount { get; private set; }\r\n        public int PageIndex { get; private set; }\r\n        public int PageSize { get; private set; }\r\n        public bool HasPreviousPage { get; private set; }\r\n        public bool HasNextPage { get; private set; }\r\n        public bool IsFirstPage { get; private set; }\r\n        public bool IsLastPage { get; private set; }\r\n\r\n    }\r\n\r\n    public static class Pagination\r\n    {\r\n        public static PagedList&amp;lt;T&amp;gt; ToPagedList&amp;lt;T&amp;gt;( this IEnumerable&amp;lt;T&amp;gt; source, int index, int pageSize )\r\n        {\r\n            return new PagedList&amp;lt;T&amp;gt;( source, index, pageSize );\r\n        }\r\n    }\r\n\r\n}');
					&lt;/script&gt;

&lt;p&gt;&lt;strong&gt;Changes from Rob's version:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Added a &amp;quot;TotalPages&amp;quot; property. 
      &lt;br /&gt;&lt;/strong&gt;If you're going to loop through each of the pages to display page navigation, you'll obviously need this. &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Changed &amp;quot;IsPreviousPage&amp;quot; to &amp;quot;HasPreviousPage&amp;quot;. 
      &lt;br /&gt;&lt;/strong&gt;It just sounds better. &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Changed &amp;quot;IsNextPage&amp;quot; to &amp;quot;HasNextPage&amp;quot;. 
      &lt;br /&gt;&lt;/strong&gt;See above. &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Added a &amp;quot;IsFirstPage&amp;quot; property. 
      &lt;br /&gt;&lt;/strong&gt;The opposite way of using the above two properties. I prefer this way, but kept the original way for backwards compatibility (except the naming). &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Added a &amp;quot;IsLastPage&amp;quot; property. 
      &lt;br /&gt;&lt;/strong&gt;See above. &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Changed the first constructor to accept IEnumerable&amp;lt;T&amp;gt; rather than IQueryable&amp;lt;T&amp;gt;. 
      &lt;br /&gt;&lt;/strong&gt;I'm not exactly sure why Rob originally made it IQueryable. I'm aware that by passing an IQueryable (LINQ) object to this constructor you'll avoid retrieving the entire set (only taking the results needed), but since IQueryable inherits from IEnumerable everything should be hunky-dory. He probably had a reason and I'm going to wind up breaking all of my stuff, but IEnumerable is just so much handier. =) &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Removed the second constructor. 
      &lt;br /&gt;&lt;/strong&gt;The second constructor took List&amp;lt;T&amp;gt;, which is unnecessary after changing the first constructor to accept IEnumerable. &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Cleaned up property declarations a bit. 
      &lt;br /&gt;&lt;/strong&gt;Mainly to make the page a bit shorter, but also to prevent the multiple calculations that could happen in the original. Also the original allowed the changing of certain properties after an instance was created, which would put the instance into an inconsistent state. &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Added argument checking and handled a few exception scenarios more gracefully. 
      &lt;br /&gt;&lt;/strong&gt;Trying to make debugging a bit friendlier. &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Removed the second extension method that didn't specify a pageSize. 
      &lt;br /&gt;&lt;/strong&gt;I don't really think that baking in an extension method that sets pageSize to 10 is a good idea, I'd prefer pageSize to be explicitly set elsewhere by the calling code. &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Moved the code to the &amp;quot;System.Collections.Generic&amp;quot; namespace. 
      &lt;br /&gt;&lt;/strong&gt;I'm sure a lot of you are breaking out in a cold sweat to see me putting something into a System.* namespace, but I kind of feel like this is something that the .Net team just &amp;quot;forgot&amp;quot;. =) Move it wherever makes you comfortable. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please note that I took many of these ideas from the commentary below Rob's original post. I'm sure many of you are using something similar, but I thought it would be useful to get something posted online that is a bit more fleshed out than the original example.&lt;/p&gt;

&lt;p&gt;Thanks for the great work Rob &amp;amp; Robert!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/Squaredroot?a=Bl3l3R"&gt;&lt;img src="http://feeds.feedburner.com/~a/Squaredroot?i=Bl3l3R" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/Squaredroot?a=EzWANUG"&gt;&lt;img src="http://feeds.feedburner.com/~f/Squaredroot?i=EzWANUG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/Squaredroot?a=k5aRWgg"&gt;&lt;img src="http://feeds.feedburner.com/~f/Squaredroot?i=k5aRWgg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Squaredroot/~4/266706712" height="1" width="1"/&gt;</description>
      <link>http://feeds.feedburner.com/~r/Squaredroot/~3/266706712/post.aspx</link>
      <author>Troy Goode</author>
      <comments>http://www.squaredroot.com/post/2008/04/Updated-PagedList-Class.aspx#comment</comments>
      <guid isPermaLink="false">http://www.squaredroot.com/post.aspx?id=20981e8e-c75b-4bf3-9d7a-bbe30dc85698</guid>
      <pubDate>Tue, 08 Apr 2008 21:33:56 -0400</pubDate>
      <category>C#</category>
      <dc:publisher>Troy Goode</dc:publisher>
      <pingback:server>http://www.squaredroot.com/pingback.axd</pingback:server>
      <pingback:target>http://www.squaredroot.com/post.aspx?id=20981e8e-c75b-4bf3-9d7a-bbe30dc85698</pingback:target>
      <slash:comments>10</slash:comments>
      <trackback:ping>http://www.squaredroot.com/trackback.axd?id=20981e8e-c75b-4bf3-9d7a-bbe30dc85698</trackback:ping>
      <wfw:comment>http://www.squaredroot.com/post/2008/04/Updated-PagedList-Class.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.squaredroot.com/syndication.axd?post=20981e8e-c75b-4bf3-9d7a-bbe30dc85698</wfw:commentRss>
    <feedburner:origLink>http://www.squaredroot.com/post.aspx?id=20981e8e-c75b-4bf3-9d7a-bbe30dc85698</feedburner:origLink></item>
    <item>
      <title>Review: Training With Stephen Walther</title>
      <description>&lt;p&gt;I just finished a four day course on AJAX, LINQ, &amp;amp; MVC taught by &lt;a href="http://www.superexpert.com/"&gt;Stephen Walther&lt;/a&gt; and wanted to let all of you know that if you are interested in training on any of these topics, I HIGHLY recommend Stephen.&lt;/p&gt;  &lt;p&gt;You can learn more about the training options he offers by visiting his training website:   &lt;br /&gt;&lt;a title="http://www.superexperttraining.com/" href="http://www.superexperttraining.com/"&gt;http://www.superexperttraining.com/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;He also keeps a blog filled with incredibly information -- and long ;-) -- posts on various aspects of ASP.Net at:   &lt;br /&gt;&lt;a title="http://weblogs.asp.net/StephenWalther/" href="http://weblogs.asp.net/StephenWalther/"&gt;http://weblogs.asp.net/StephenWalther/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Read on for more details about my experiences this week.&lt;/p&gt;  &lt;h1&gt;The Instructor&lt;/h1&gt;  &lt;p&gt;Stephen is a successful author, having literally &amp;quot;written the book&amp;quot; on ASP.Net (and even ASP Classic!). His book &amp;quot;ASP.NET 3.5 Unleashed&amp;quot; has received excellent reviews from Amazon and I look forward to reading it soon.&lt;/p&gt;  &lt;p&gt;You can buy Stephen's book from Amazon here:&lt;/p&gt;  &lt;p style="text-align: center"&gt;&lt;a href="http://www.amazon.com/gp/product/0672330113"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="213" alt="AspNet3Unleashed" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/TrainingWithStephenWalther_CD21/AspNet3Unleashed_3.jpg" width="164" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;We all found Stephen to be very personable and he obviously has an excellent command on the language and tools available in the .Net ecosystem. Also, anyone that can put up with my constant interruptions and derails for four days in a windowless classroom is clearly a pro. =)&lt;/p&gt;  &lt;h1&gt;The Course&lt;/h1&gt;  &lt;p&gt;&lt;a href="http://www.dannydouglass.com/"&gt;Danny Douglass&lt;/a&gt; originally contacted Stephen to request that he teach a class for seven of our developers at &lt;a href="http://www.nreca.coop/"&gt;the organization we work for&lt;/a&gt;. Stephen was kind enough to then customize a course around the technologies we had requested, and that is how we ended up with a one day primer on LINQ &amp;amp; MVC followed by an in-depth training session on AJAX technologies and Microsoft's ASP.Net AJAX implementation specifically.&lt;/p&gt;  &lt;p&gt;As anyone that reads my blog regularly knows, I am heavily invested in learning the MVC framework and was highly impressed by Stephens grasp on such a new technology. We may very well have been the first ASP.Net MVC class that anyone has taught anywhere and Stephen managed to teach it quickly and confidently. I was also impressed that he was teaching us things based upon the Preview 2 release of the MVC framework which has only been available publicly for 3 weeks rather than the older December CTP release.&lt;/p&gt;  &lt;p&gt;As someone that considers himself a strong JavaScript developer (but weak at AJAX), I came into the class a little worried that the JavaScript explanation portions of the program would be more remedial than I wanted. I was wrong. Stephen led a thorough review over the advanced JavaScript features developers need to know to develop world-class AJAX libraries and did so while keeping the pace brisk and managing not to leave anyone in the room behind.&lt;/p&gt;  &lt;p&gt;As I said above, I recommend Stephen's training courses to anyone organization interested in learning AJAX, JavaScript, MVC, LINQ, or ASP.Net in general. Thanks for the excellent class Stephen!&lt;/p&gt;  &lt;p&gt;&lt;em&gt;&lt;strong&gt;Disclaimer: I was not paid or compensated in any way for this endorsement.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/Squaredroot?a=XLB8ZF"&gt;&lt;img src="http://feeds.feedburner.com/~a/Squaredroot?i=XLB8ZF" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/Squaredroot?a=stxcF3G"&gt;&lt;img src="http://feeds.feedburner.com/~f/Squaredroot?i=stxcF3G" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/Squaredroot?a=MBEzAfg"&gt;&lt;img src="http://feeds.feedburner.com/~f/Squaredroot?i=MBEzAfg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Squaredroot/~4/264157169" height="1" width="1"/&gt;</description>
      <link>http://feeds.feedburner.com/~r/Squaredroot/~3/264157169/post.aspx</link>
      <author>Troy Goode</author>
      <comments>http://www.squaredroot.com/post/2008/04/Training-with-Stephen-Walther.aspx#comment</comments>
      <guid isPermaLink="false">http://www.squaredroot.com/post.aspx?id=fe3d36f5-1064-4e71-ba08-b04f67d0f1c4</guid>
      <pubDate>Fri, 04 Apr 2008 15:06:17 -0400</pubDate>
      <category>MVC</category>
      <dc:publisher>Troy Goode</dc:publisher>
      <pingback:server>http://www.squaredroot.com/pingback.axd</pingback:server>
      <pingback:target>http://www.squaredroot.com/post.aspx?id=fe3d36f5-1064-4e71-ba08-b04f67d0f1c4</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://www.squaredroot.com/trackback.axd?id=fe3d36f5-1064-4e71-ba08-b04f67d0f1c4</trackback:ping>
      <wfw:comment>http://www.squaredroot.com/post/2008/04/Training-with-Stephen-Walther.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.squaredroot.com/syndication.axd?post=fe3d36f5-1064-4e71-ba08-b04f67d0f1c4</wfw:commentRss>
    <feedburner:origLink>http://www.squaredroot.com/post.aspx?id=fe3d36f5-1064-4e71-ba08-b04f67d0f1c4</feedburner:origLink></item>
    <item>
      <title>MVC: Membership Starter Kit</title>
      <description>&lt;blockquote&gt; &lt;p&gt;A newer version of the Membership Starter Kit is now available. &lt;a href="http://www.squaredroot.com/post/2008/04/MVC-Membership-Starter-Kit-11.aspx"&gt;Click here&lt;/a&gt; to see what has changed.&lt;/p&gt;&lt;/blockquote&gt; &lt;h1&gt;Introduction&lt;/h1&gt; &lt;p&gt;One of my very first blog posts (and most definitely my most popular so far) revolved around &lt;a href="http://www.squaredroot.com/post/2007/12/ASPNet-MVC-Membership-Basics.aspx"&gt;how to integrate ASP.Net membership and forms authentication into the ASP.Net MVC framework&lt;/a&gt; which had just been released in it's December CTP flavor. It has remained popular to this day, but unfortunately the Preview 2 release of the MVC framework has caused much of the code I released in that article to no longer function correctly. &lt;/p&gt; &lt;p&gt;Even before the release of Preview 2, I had been planning to extend the samples I was providing to offer more useful features. I don't know about you, but nearly every website I ever create with ASP.Net requires some kind of security/membership system. My preference is to use the built-in system when possible (except for the horrible Profiles sub-system). This means creating login, logout, &amp;amp; registration functionality every time, as well as creating administrative screens for managing the users that enter your system. &lt;/p&gt; &lt;p&gt;WebForms provides some controls to help with the login and registration process, but user administration has always been delegated to either (a) the built-in tool that runs separately and doesn't work remotely or (b) rolling your own solution. The development of the MVC framework seems to me like a good time to resolve this scenario and provide the community with an array of pre-built tools to help boot-strap projects so that we can stop working on infrastructure and start working on the heart of the individual application. &lt;/p&gt; &lt;p&gt;&lt;strong&gt;With that in mind I have created a CodePlex project: the &lt;/strong&gt;&lt;a href="http://www.codeplex.com/MvcMembership"&gt;&lt;strong&gt;ASP.Net MVC Membership Starter Kit&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt; It currently provides controllers and views for all of the common authentication and user administration needs, including: &lt;/p&gt; &lt;ul&gt; &lt;li&gt;Login/Logout  &lt;li&gt;Registration  &lt;li&gt;List of Registered Users  &lt;li&gt;User Details / Administration  &lt;li&gt;Role Management &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;A big thanks goes out to Rob Conery, as I borrowed his recent &lt;a href="http://blog.wekeroad.com/blog/aspnet-mvc-securing-your-controller-actions/"&gt;Authentication Filters&lt;/a&gt; and included those, along with my recently released &lt;a href="http://www.squaredroot.com/post/2008/04/MVC-Error-Handler-Filter.aspx"&gt;Error Handling Filters&lt;/a&gt;. &lt;/p&gt; &lt;p&gt;Okay, enough wall o'text. Let's take a look at some screenshots: &lt;/p&gt; &lt;h1&gt;Screenshot Tour&lt;/h1&gt; &lt;p&gt;Here is the menu when you first log in: &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/Menu-LoggedOut_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="72" alt="Menu-LoggedOut" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/Menu-LoggedOut_thumb.jpg" width="377" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;The registration page: &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/Registration_4.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="240" alt="Registration" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/Registration_thumb_1.jpg" width="219" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;The login page (note that the Administrator's credentials are displayed to make it easy to get started, you'll obviously want to change them and remove that note): &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/Login_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="216" alt="Login" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/Login_thumb.jpg" width="240" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Having logged in, here is what the menu looks like now: &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/Menu-LoggedIn_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="68" alt="Menu-LoggedIn" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/Menu-LoggedIn_thumb.jpg" width="380" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;The current options upon clicking the Security tab: &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/Security_2.jpg"&gt;&lt;img height="157" alt="Security" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/Security_thumb.jpg" width="147" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Clicking "Manage Users" brings you to a list of all users currently registered: &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/ManageUsers_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="105" alt="ManageUsers" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/ManageUsers_thumb.jpg" width="171" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Clicking on the user takes you to a form that allows you to view their details and edit a few aspects of their profile... &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/User-Top_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="240" alt="User-Top" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/User-Top_thumb.jpg" width="196" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;as well as view/change the roles they are in and help with password issues: &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/User-Bottom_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="240" alt="User-Bottom" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/User-Bottom_thumb.jpg" width="182" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;From the Security tab you can also go to a list of all the system's roles, from which you can add/delete roles as you need: &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/Roles_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="264" alt="Roles" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/Roles_thumb.jpg" width="426" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Clicking on a role from the roles list or the user profile allows you to view/modify the users in that role: &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/UsersInRole_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="147" alt="UsersInRole" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/UsersInRole_thumb.jpg" width="428" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;And finally, the Security tab offers a link to another registration form, geared toward Administrators: &lt;/p&gt; &lt;p&gt;&lt;a href="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/CreateUser_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="240" alt="CreateUser" src="http://www.squaredroot.com/image.axd?picture=WindowsLiveWriter/MVCMembershipStarterKit_F5A6/CreateUser_thumb.jpg" width="230" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;h1&gt;NSFAQ (Not-So Frequently Asked Questions)&lt;/h1&gt; &lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; Does this compete with MvcContrib? &lt;br&gt;&lt;strong&gt;A:&lt;/strong&gt; No. &lt;a href="http://www.codeplex.com/MVCContrib"&gt;MvcContrib&lt;/a&gt; is a great project that aims to features like alternate routing and view engines, and IoC integration. This project is simply a starter kit to help get membership-based applications off the ground a little quicker. There is no reason you could not use both projects together. &lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; What dependencies does using this starter kit saddle me with? &lt;br&gt;&lt;strong&gt;A:&lt;/strong&gt; Ideally, none, other than the ASP.Net Membership API. Every measure will be taken to avoid using third party libraries, be it JavaScript or .Net. We will strive to separate the code and rely on default settings as much as possible to make it easy for you to customize your installation without anything in the starter kit getting in the way. &lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; Who is responsible for this? &lt;br&gt;&lt;strong&gt;A:&lt;/strong&gt; Currently, only &lt;a href="http://www.squaredroot.com/page/About-Me.aspx"&gt;me&lt;/a&gt;, but I'd like that to change! I'm keenly interested in finding a few other developers that would like to contribute to enhancing the starter kit. Please &lt;a href="http://www.squaredroot.com/page/About-Me.aspx#ContactInformation"&gt;contact me&lt;/a&gt; if you'd like to help! &lt;/p&gt; &lt;h1&gt;What's Next?&lt;/h1&gt; &lt;p&gt;There are a few features missing that I would like to include in the very short term. Primarily these are features for end-users, like Change Password and Forgot My Password (both of which are currently available on the administration side). Beyond that, visual cleanup of the forms (and separation of the style sheets) as well as a bit of AJAX-ification of the forms would be nice. If you use the starter kit and have suggestions or criticisms, please post to the &lt;a href="http://www.codeplex.com/MvcMembership/Thread/List.aspx"&gt;Discussions forum&lt;/a&gt; or &lt;a href="http://www.codeplex.com/MvcMembership/WorkItem/List.aspx"&gt;Issue Tracker&lt;/a&gt;! &lt;/p&gt; &lt;p&gt;You can download the latest release from &lt;a href="http://www.codeplex.com/MvcMembership"&gt;the CodePlex project&lt;/a&gt;. I hope you all find it useful! &lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/Squaredroot?a=LhvnUC"&gt;&lt;img src="http://feeds.feedburner.com/~a/Squaredroot?i=LhvnUC" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/Squaredroot?a=b4bEleG"&gt;&lt;img src="http://feeds.feedburner.com/~f/Squaredroot?i=b4bEleG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/Squaredroot?a=MlNqGFg"&gt;&lt;img src="http://feeds.feedburner.com/~f/Squaredroot?i=MlNqGFg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Squaredroot/~4/262949895" height="1" width="1"/&gt;</description>
      <link>http://feeds.feedburner.com/~r/Squaredroot/~3/262949895/post.aspx</link>
      <author>Troy Goode</author>
      <comments>http://www.squaredroot.com/post/2008/04/MVC-Membership-Starter-Kit.aspx#comment</comments>
      <guid isPermaLink="false">http://www.squaredroot.com/post.aspx?id=75be66d2-e1bc-4919-bab7-dadff6d1fc0e</guid>
      <pubDate>Wed, 02 Apr 2008 18:43:00 -0400</pubDate>
      <category>MVC</category>
      <dc:publisher>Troy Goode</dc:publisher>
      <pingback:server>http://www.squaredroot.com/pingback.axd</pingback:server>
      <pingback:target>http://www.squaredroot.com/post.aspx?id=75be66d2-e1bc-4919-bab7-dadff6d1fc0e</pingback:target>
      <slash:comments>23</slash:comments>
      <trackback:ping>http://www.squaredroot.com/trackback.axd?id=75be66d2-e1bc-4919-bab7-dadff6d1fc0e</trackback:ping>
      <wfw:comment>http://www.squaredroot.com/post/2008/04/MVC-Membership-Starter-Kit.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.squaredroot.com/syndication.axd?post=75be66d2-e1bc-4919-bab7-dadff6d1fc0e</wfw:commentRss>
    <feedburner:origLink>http://www.squaredroot.com/post.aspx?id=75be66d2-e1bc-4919-bab7-dadff6d1fc0e</feedburner:origLink></item>
    <item>
      <title>MVC: Action Filter for Handling Errors</title>
      <description>&lt;p&gt;
A few months ago I posted &lt;a href="http://www.squaredroot.com/post/2008/01/MVC-Authentication-and-Errors.aspx"&gt;an article and some code&lt;/a&gt; that contained filters for forms authentication and error handling for the Preview 1 (CTP) release of the MVC framework. Unfortunately &lt;a href="http://blogs.msdn.com/brada/archive/2008/03/05/asp-net-mvc-preview-2.aspx"&gt;the Preview 2 release&lt;/a&gt; that was made available a few weeks ago changed enough that the code I posted no longer works. 
&lt;/p&gt;
&lt;p&gt;
What the Preview 2 release did provide, however, was a new built-in filter framework. Rob Conery has already gone through the trouble of &lt;a href="http://blog.wekeroad.com/blog/aspnet-mvc-securing-your-controller-actions/"&gt;creating authentication filters&lt;/a&gt; that cover most of the functionality I had before, but I have yet to see an implementation of a filter for error handling that I like. I&amp;#39;ve gone ahead and started from scratch, throwing away my old filters, and created a new filter that I think covers most of the same scenarios as my old ErrorHandler filters while being much simpler to implement and use. Hopefully you&amp;#39;ll find it useful. 
&lt;/p&gt;
&lt;p&gt;
First let&amp;#39;s take a look at a simple use case scenario: 
&lt;/p&gt;
&lt;div class="csharpcode-wrapper"&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Product( &lt;span class="kwrd"&gt;int&lt;/span&gt;? id )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt; {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt;( id == &lt;span class="kwrd"&gt;null&lt;/span&gt; )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt;         &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException( &lt;span class="str"&gt;&amp;quot;No Product ID&amp;quot;&lt;/span&gt; );
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;     RenderView( &lt;span class="str"&gt;&amp;quot;DisplayProduct&amp;quot;&lt;/span&gt;, GetProduct(id.Value) );
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt; }
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="CopyToClipboard" style=""&gt;&lt;div&gt;&lt;a href="javascript:void(0);" onclick="CopyToClipboard_ViewPlain(copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_1208);"&gt;View Plain&lt;/a&gt; | &lt;a href="javascript:void(0);" onclick="CopyToClipboard_Copy(copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_1208);"&gt;Copy To Clipboard&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
					&lt;script type="text/javascript"&gt;
						var copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_1208 = CopyToClipboard_Strip('public void Product( int? id )\r\n{\r\n    if( id == null )\r\n        throw new ArgumentNullException( &amp;quot;No Product ID&amp;quot; );\r\n    RenderView( &amp;quot;DisplayProduct&amp;quot;, GetProduct(id.Value) );\r\n}\r\n');
					&lt;/script&gt;
&lt;p&gt;
In the code above, we have a simple action that displays a product based upon the ID specified. What do we do when no ID is specified though? The &amp;quot;correct&amp;quot; thing to do seems to be to throw an exception, as we&amp;#39;ve done, but now the user will see either (a) an ugly 500 error screen [worst case] or (b) be redirected to the generic error page [best case]. Sometimes we&amp;#39;d like a bit more control than that though... 
&lt;/p&gt;
&lt;p&gt;
Let&amp;#39;s go ahead and add our error handling filter to this action and tell it that whenever &lt;strong&gt;ArgumentNullException&lt;/strong&gt; is thrown, redirect to the &amp;quot;Products&amp;quot; page, where the user can select a product with a valid ID. 
&lt;/p&gt;
&lt;div class="csharpcode-wrapper"&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; [RedirectToUrlOnError(Type=&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ArgumentNullException),Url=&lt;span class="str"&gt;&amp;quot;/Products&amp;quot;&lt;/span&gt;)]
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Product( &lt;span class="kwrd"&gt;int&lt;/span&gt;? id )
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt; {
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt;( id == &lt;span class="kwrd"&gt;null&lt;/span&gt; )
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;         &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException( &lt;span class="str"&gt;&amp;quot;No Product ID&amp;quot;&lt;/span&gt; );
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;     RenderView( &lt;span class="str"&gt;&amp;quot;DisplayProduct&amp;quot;&lt;/span&gt;, GetProduct(id.Value) );
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt; }
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="CopyToClipboard" style=""&gt;&lt;div&gt;&lt;a href="javascript:void(0);" onclick="CopyToClipboard_ViewPlain(copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_3467);"&gt;View Plain&lt;/a&gt; | &lt;a href="javascript:void(0);" onclick="CopyToClipboard_Copy(copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_3467);"&gt;Copy To Clipboard&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
					&lt;script type="text/javascript"&gt;
						var copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_3467 = CopyToClipboard_Strip('[RedirectToUrlOnError(Type=typeof(ArgumentNullException),Url=&amp;quot;/Products&amp;quot;)]\r\npublic void Product( int? id )\r\n{\r\n    if( id == null )\r\n        throw new ArgumentNullException( &amp;quot;No Product ID&amp;quot; );\r\n    RenderView( &amp;quot;DisplayProduct&amp;quot;, GetProduct(id.Value) );\r\n}\r\n');
					&lt;/script&gt;
&lt;p&gt;
So we&amp;#39;ve added a [&lt;strong&gt;RedirectToUrlOnError&lt;/strong&gt;] attribute and supplied it with a &lt;strong&gt;Type&lt;/strong&gt; property - detailing the exception to catch - and a &lt;strong&gt;Url&lt;/strong&gt; property - specifying the &lt;strong&gt;Url&lt;/strong&gt; to navigate to upon a matched exception. You&amp;#39;ll notice we are making a call to the &lt;strong&gt;GetProduct&lt;/strong&gt;(&lt;em&gt;int&lt;/em&gt;) method to retrieve the product&amp;#39;s model so that we can pass it into the view&amp;#39;s ViewData. What if this method were to fail? What if we weren&amp;#39;t entirely certain what exception it would throw, or maybe we didn&amp;#39;t care, we just want to handle any exception except for &lt;strong&gt;ArgumentNullException&lt;/strong&gt; (which is already being handled). In this case we&amp;#39;ll add another filter, but this time we will not specify the &lt;strong&gt;Type&lt;/strong&gt; of exception that it should catch and just tell it that if anything isn&amp;#39;t caught by another error handler redirect to the homepage. 
&lt;/p&gt;
&lt;div class="csharpcode-wrapper"&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; [RedirectToUrlOnError(Type=&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ArgumentNullException),Url=&lt;span class="str"&gt;&amp;quot;/Products&amp;quot;&lt;/span&gt;)]
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt; [RedirectToUrlOnError(Url=&lt;span class="str"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;)]
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Product( &lt;span class="kwrd"&gt;int&lt;/span&gt;? id )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt; {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt;( id == &lt;span class="kwrd"&gt;null&lt;/span&gt; )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;         &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException( &lt;span class="str"&gt;&amp;quot;No Product ID&amp;quot;&lt;/span&gt; );
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt;     RenderView( &lt;span class="str"&gt;&amp;quot;DisplayProduct&amp;quot;&lt;/span&gt;, GetProduct(id.Value) );
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt; }
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="CopyToClipboard" style=""&gt;&lt;div&gt;&lt;a href="javascript:void(0);" onclick="CopyToClipboard_ViewPlain(copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_6282);"&gt;View Plain&lt;/a&gt; | &lt;a href="javascript:void(0);" onclick="CopyToClipboard_Copy(copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_6282);"&gt;Copy To Clipboard&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
					&lt;script type="text/javascript"&gt;
						var copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_6282 = CopyToClipboard_Strip('[RedirectToUrlOnError(Type=typeof(ArgumentNullException),Url=&amp;quot;/Products&amp;quot;)]\r\n[RedirectToUrlOnError(Url=&amp;quot;/&amp;quot;)]\r\npublic void Product( int? id )\r\n{\r\n    if( id == null )\r\n        throw new ArgumentNullException( &amp;quot;No Product ID&amp;quot; );\r\n    RenderView( &amp;quot;DisplayProduct&amp;quot;, GetProduct(id.Value) );\r\n}\r\n');
					&lt;/script&gt;
&lt;p&gt;
You can have as many error handler filters attached to an action as you need, but only one may have no Type specified. 
&lt;/p&gt;
&lt;p&gt;
Now let&amp;#39;s take a look at the code for the filter itself:
&lt;/p&gt;
&lt;div class="csharpcode-wrapper"&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.Mvc;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt; &lt;span class="kwrd"&gt;namespace&lt;/span&gt; SquaredRoot.Mvc.Filters.ErrorHandling
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt; {
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; RedirectToUrlOnErrorAttribute : RedirectOnErrorAttribute
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;     {
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Url{ get; set; }
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  12:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  13:&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;bool&lt;/span&gt; Validate( FilterExecutedContext filterContext )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  14:&lt;/span&gt;         {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  15:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  16:&lt;/span&gt;             &lt;span class="rem"&gt;//### the url property is always needed&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  17:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;( &lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty( Url ) || Url.Trim() == &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  18:&lt;/span&gt;                 &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException( &lt;span class="str"&gt;&amp;quot;RedirectToUrlOnErrorAttribute&amp;#39;s Url property must have a value.&amp;quot;&lt;/span&gt; );
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  19:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  20:&lt;/span&gt;             &lt;span class="rem"&gt;//### continue execution&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  21:&lt;/span&gt;             &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  22:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  23:&lt;/span&gt;         }
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  24:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  25:&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; Redirect( FilterExecutedContext filterContext )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  26:&lt;/span&gt;         {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  27:&lt;/span&gt;             filterContext.ExceptionHandled = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  28:&lt;/span&gt;             filterContext.HttpContext.Response.Redirect( Url, &lt;span class="kwrd"&gt;true&lt;/span&gt; );
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  29:&lt;/span&gt;         }
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  30:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  31:&lt;/span&gt;     }
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  32:&lt;/span&gt; }
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="CopyToClipboard" style=""&gt;&lt;div&gt;&lt;a href="javascript:void(0);" onclick="CopyToClipboard_ViewPlain(copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_8510);"&gt;View Plain&lt;/a&gt; | &lt;a href="javascript:void(0);" onclick="CopyToClipboard_Copy(copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_8510);"&gt;Copy To Clipboard&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
					&lt;script type="text/javascript"&gt;
						var copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_8510 = CopyToClipboard_Strip('using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Web.Mvc;\r\n \r\nnamespace SquaredRoot.Mvc.Filters.ErrorHandling\r\n{\r\n    public class RedirectToUrlOnErrorAttribute : RedirectOnErrorAttribute\r\n    {\r\n \r\n        public string Url{ get; set; }\r\n \r\n        protected override bool Validate( FilterExecutedContext filterContext )\r\n        {\r\n \r\n            //### the url property is always needed\r\n            if( string.IsNullOrEmpty( Url ) || Url.Trim() == string.Empty )\r\n                throw new ArgumentNullException( &amp;quot;RedirectToUrlOnErrorAttribute&amp;#39;s Url property must have a value.&amp;quot; );\r\n \r\n            //### continue execution\r\n            return true;\r\n \r\n        }\r\n \r\n        protected override void Redirect( FilterExecutedContext filterContext )\r\n        {\r\n            filterContext.ExceptionHandled = true;\r\n            filterContext.HttpContext.Response.Redirect( Url, true );\r\n        }\r\n \r\n    }\r\n}\r\n');
					&lt;/script&gt;
&lt;p&gt;
So the [&lt;strong&gt;RedirectToUrlOnError&lt;/strong&gt;] attribute inherits from the [&lt;strong&gt;RedirectOnError&lt;/strong&gt;] attribute, which is where most of the hard work is done. We&amp;#39;ll take a look at that base class in a bit, but first let&amp;#39;s look at the other attribute you can use to trap and respond to errors - the [&lt;strong&gt;RedirectToActionOnError&lt;/strong&gt;] attribute. We&amp;#39;ll continue with the &lt;strong&gt;Product&lt;/strong&gt;(&lt;em&gt;id&lt;/em&gt;) sample from above, but this time redirect to an action rather than a hardcoded Url:
&lt;/p&gt;
&lt;div class="csharpcode-wrapper"&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; [RedirectToActionOnError(
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt;     Type=&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ArgumentNullException),
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt;     Controller=&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ProductController),
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt;     Action=&lt;span class="str"&gt;&amp;quot;Index&amp;quot;&lt;/span&gt; )]
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt; [RedirectToUrlOnError(Url=&lt;span class="str"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;)]
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Product( &lt;span class="kwrd"&gt;int&lt;/span&gt;? id )
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt; {
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt;( id == &lt;span class="kwrd"&gt;null&lt;/span&gt; )
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;         &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException( &lt;span class="str"&gt;&amp;quot;No Product ID&amp;quot;&lt;/span&gt; );
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;     RenderView( &lt;span class="str"&gt;&amp;quot;DisplayProduct&amp;quot;&lt;/span&gt;, GetProduct(id.Value) );
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt; }
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="CopyToClipboard" style=""&gt;&lt;div&gt;&lt;a href="javascript:void(0);" onclick="CopyToClipboard_ViewPlain(copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_14262);"&gt;View Plain&lt;/a&gt; | &lt;a href="javascript:void(0);" onclick="CopyToClipboard_Copy(copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_14262);"&gt;Copy To Clipboard&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
					&lt;script type="text/javascript"&gt;
						var copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_14262 = CopyToClipboard_Strip('[RedirectToActionOnError(\r\n    Type=typeof(ArgumentNullException),\r\n    Controller=typeof(ProductController),\r\n    Action=&amp;quot;Index&amp;quot; )]\r\n[RedirectToUrlOnError(Url=&amp;quot;/&amp;quot;)]\r\npublic void Product( int? id )\r\n{\r\n    if( id == null )\r\n        throw new ArgumentNullException( &amp;quot;No Product ID&amp;quot; );\r\n    RenderView( &amp;quot;DisplayProduct&amp;quot;, GetProduct(id.Value) );\r\n}\r\n');
					&lt;/script&gt;
&lt;p&gt;
You can see that this time instead of providing the Url property we are using providing the type of the controller that contains our target action, and the name of the action as a string. (Unfortunately lambda expressions are not allowed as parameters to an attribute, so I was limited in my options here. If you have a better idea, please let me know!) Also note that the catch-all is still there as a [&lt;strong&gt;RedirectToUrlOnError&lt;/strong&gt;] attribute. You may use the [&lt;strong&gt;RedirectToActionOnError&lt;/strong&gt;] attribute as a catch-all and you can mix and match the two attribute types, but still only one catch-all attribute total is allowed per action (in other words, you cannot have one of each).
&lt;/p&gt;
&lt;p&gt;
Now let&amp;#39;s see the code for this filter:
&lt;/p&gt;
&lt;div class="csharpcode-wrapper"&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.Mvc;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.Routing;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt; &lt;span class="kwrd"&gt;namespace&lt;/span&gt; SquaredRoot.Mvc.Filters.ErrorHandling
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt; {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; RedirectToActionOnErrorAttribute : RedirectOnErrorAttribute
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;     {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  12:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; Type Controller{ get; set; }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  13:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Action{ get; set; }
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  14:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  15:&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;bool&lt;/span&gt; Validate( FilterExecutedContext filterContext )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  16:&lt;/span&gt;         {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  17:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  18:&lt;/span&gt;             &lt;span class="rem"&gt;//### the url property is always needed&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  19:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;(
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  20:&lt;/span&gt;                 Controller == &lt;span class="kwrd"&gt;null&lt;/span&gt; ||
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  21:&lt;/span&gt;                 ( &lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty( Action ) || Action.Trim() == &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  22:&lt;/span&gt;             )
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  23:&lt;/span&gt;                 &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException( &lt;span class="str"&gt;&amp;quot;RedirectToUrlOnActionAttribute&amp;#39;s Controller and Action properties must have values.&amp;quot;&lt;/span&gt; );
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  24:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  25:&lt;/span&gt;             &lt;span class="rem"&gt;//### make sure the Contoller property is a Controller&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  26:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;( !&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(System.Web.Mvc.Controller).IsAssignableFrom( Controller ) )
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  27:&lt;/span&gt;                 &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentException( &lt;span class="str"&gt;&amp;quot;RedirectToUrlOnActionAttribute&amp;#39;s Controller property&amp;#39;s value must derive from System.Web.Mvc.Controller.&amp;quot;&lt;/span&gt; );
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  28:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  29:&lt;/span&gt;             &lt;span class="rem"&gt;//### continue processing&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  30:&lt;/span&gt;             &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  31:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  32:&lt;/span&gt;         }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  33:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  34:&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; Redirect( FilterExecutedContext filterContext )
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  35:&lt;/span&gt;         {
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  36:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  37:&lt;/span&gt;             &lt;span class="rem"&gt;//### turn &amp;quot;Foo.Foo.Foo.BarController&amp;quot; into &amp;quot;Bar&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  38:&lt;/span&gt;             &lt;span class="kwrd"&gt;string&lt;/span&gt; controllerName = Controller.ToString();
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  39:&lt;/span&gt;             controllerName = controllerName.Substring( controllerName.LastIndexOf(&lt;span class="str"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;) + 1 );
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  40:&lt;/span&gt;             controllerName = controllerName.Substring( 0, controllerName.LastIndexOf(&lt;span class="str"&gt;&amp;quot;Controller&amp;quot;&lt;/span&gt;) );
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  41:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  42:&lt;/span&gt;             &lt;span class="rem"&gt;//### turn route data into url&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  43:&lt;/span&gt;             RouteValueDictionary rvd = &lt;span class="kwrd"&gt;new&lt;/span&gt; RouteValueDictionary( &lt;span class="kwrd"&gt;new&lt;/span&gt;{
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  44:&lt;/span&gt;                 controller = controllerName,
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  45:&lt;/span&gt;                 action = Action
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  46:&lt;/span&gt;             } );
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  47:&lt;/span&gt;             ControllerContext ctx = &lt;span class="kwrd"&gt;new&lt;/span&gt; ControllerContext(
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  48:&lt;/span&gt;                 filterContext.HttpContext,
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  49:&lt;/span&gt;                 filterContext.RouteData,
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  50:&lt;/span&gt;                 filterContext.Controller
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  51:&lt;/span&gt;             );
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  52:&lt;/span&gt;             VirtualPathData vpd = RouteTable.Routes.GetVirtualPath( ctx, rvd );
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  53:&lt;/span&gt;             &lt;span class="kwrd"&gt;string&lt;/span&gt; url = vpd.VirtualPath;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  54:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  55:&lt;/span&gt;             &lt;span class="rem"&gt;//### redirect&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  56:&lt;/span&gt;             filterContext.ExceptionHandled = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  57:&lt;/span&gt;             filterContext.HttpContext.Response.Redirect( url, &lt;span class="kwrd"&gt;true&lt;/span&gt; );
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  58:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  59:&lt;/span&gt;         }
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  60:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  61:&lt;/span&gt;     }
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  62:&lt;/span&gt; }
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="CopyToClipboard" style=""&gt;&lt;div&gt;&lt;a href="javascript:void(0);" onclick="CopyToClipboard_ViewPlain(copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_17388);"&gt;View Plain&lt;/a&gt; | &lt;a href="javascript:void(0);" onclick="CopyToClipboard_Copy(copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_17388);"&gt;Copy To Clipboard&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
					&lt;script type="text/javascript"&gt;
						var copyToClipboard1bb70e0ade6e48ffb6e42613f396846f_17388 = CopyToClipboard_Strip('using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Web.Mvc;\r\nusing System.Web.Routing;\r\n \r\nnamespace SquaredRoot.Mvc.Filters.ErrorHandling\r\n{\r\n    public class RedirectToActionOnErrorAttribute : RedirectOnErrorAttribute\r\n    {\r\n \r\n        public Type Controller{ get; set; }\r\n        public string Action{ get; set; }\r\n \r\n        protected override bool Validate( FilterExecutedContext filterContext )\r\n        {\r\n \r\n            //### the url property is always needed\r\n            if(\r\n                Controller == null ||\r\n                ( string.IsNullOrEmpty( Action ) || Action.Trim() == string.Empty )\r\n            )\r\n                throw new ArgumentNullException( &amp;quot;RedirectToUrlOnActionAttribute&amp;#39;s Controller and Action properties must have values.&amp;quot; );\r\n \r\n            //### make sure the Contoller property is a Controller\r\n            if( !typeof(System.Web.Mvc.Controller).IsAssignableFrom( Controller ) )\r\n                throw new ArgumentException( &amp;quot;RedirectToUrlOnActionAttribute&amp;#39;s Controller property&amp;#39;s value must derive from System.Web.Mvc.Controller.&amp;quot; );\r\n \r\n            //### continue processing\r\n            return true;\r\n \r\n        }\r\n \r\n        protected override void Redirect( FilterExecutedContext filterContext )\r\n        {\r\n \r\n            //### turn &amp;quot;Foo.Foo.Foo.BarController&amp;quot; into &amp;quot;Bar&amp;quot;\r\n            string controllerName = Controller.ToString();\r\n            controllerName = controllerName.Substring( controllerName.LastIndexOf(&amp;quot;.&amp;quot;) + 1 );\r\n            controllerName = controllerName.Substring( 0, controllerName.LastIndexOf(&amp;quot;Controller&amp;quot;) );\r\n \r\n            //### turn route data into url\r\n            RouteValueDictionary rvd = new RouteValueDictionary( new{\r\n                controller = controllerName,\r\n                action = Action\r\n            } );\r\n            ControllerContext ctx = new ControllerContext(\r\n                filterContext.HttpContext,\r\n                filterContext.RouteData,\r\n                filterContext.Controller\r\n            );\r\n            VirtualPathData vpd = RouteTable.Routes.GetVirtualPath( ctx, rvd );\r\n            string url = vpd.VirtualPath;\r\n \r\n            //### redirect\r\n            filterContext.ExceptionHandled = true;\r\n            filterContext.HttpContext.Response.Redirect( url, true );\r\n \r\n        }\r\n \r\n    }\r\n}\r\n');
					&lt;/script&gt;
&lt;p&gt;
Other than some complexity with determining the Url, everything is very similar to the other filter. Again it appears the base class is doing the heavy lifting. Let&amp;#39;s finally take a look at that base class:
&lt;/p&gt;
&lt;div class="csharpcode-wrapper"&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   2:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   3:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   4:&lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.Mvc;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   5:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   6:&lt;/span&gt; &lt;span class="kwrd"&gt;namespace&lt;/span&gt; SquaredRoot.Mvc.Filters.ErrorHandling
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   7:&lt;/span&gt; {
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;   8:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; RedirectOnErrorAttribute : ActionFilterAttribute
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;   9:&lt;/span&gt;     {
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  10:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  11:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; Type Type { get; set; }
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  12:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  13:&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; OnActionExecuted( FilterExecutedContext filterContext )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  14:&lt;/span&gt;         {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  15:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  16:&lt;/span&gt;             &lt;span class="rem"&gt;//### check for errors&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  17:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;( !Validate(filterContext) )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  18:&lt;/span&gt;                 &lt;span class="kwrd"&gt;return&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  19:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  20:&lt;/span&gt;             &lt;span class="rem"&gt;//### make sure the Type property is an Exception&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  21:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;( Type != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; !&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(System.Exception).IsAssignableFrom( Type ) )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  22:&lt;/span&gt;                 &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentException( &lt;span class="str"&gt;&amp;quot;RedirectOnErrorAttribute&amp;#39;s Type property&amp;#39;s value must derive from System.Exception.&amp;quot;&lt;/span&gt; );
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  23:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  24:&lt;/span&gt;             &lt;span class="rem"&gt;//### if no exception occurred, stop processing this filter&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  25:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;( filterContext.Exception == &lt;span class="kwrd"&gt;null&lt;/span&gt; )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  26:&lt;/span&gt;                 &lt;span class="kwrd"&gt;return&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  27:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  28:&lt;/span&gt;             &lt;span class="rem"&gt;//### get inner exception unless it is null (this should never happen?)&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  29:&lt;/span&gt;             Exception ex = filterContext.Exception.InnerException ?? filterContext.Exception;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  30:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  31:&lt;/span&gt;             &lt;span class="rem"&gt;//### if exception was thrown because of Response.Redirect, ignore it&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  32:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;( ex.GetType() == &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(System.Threading.ThreadAbortException) )
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  33:&lt;/span&gt;                 &lt;span class="kwrd"&gt;return&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  34:&lt;/span&gt;             &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;( Type == &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(System.Threading.ThreadAbortException) )
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  35:&lt;/span&gt;                 &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentException( &lt;span class="str"&gt;&amp;quot;Cannot catch exceptions of type &amp;#39;ThreadAbortException&amp;#39;.&amp;quot;&lt;/span&gt; );
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  36:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  37:&lt;/span&gt;             &lt;span class="rem"&gt;//### if the specified Type matches the thrown exception, process it&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  38:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;( IsExactMatch(ex) )
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  39:&lt;/span&gt;                 Redirect( filterContext );
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  40:&lt;/span&gt;             &lt;span class="rem"&gt;//### if this attribute has no specified Type, investigate further (this attribute is a catch-all error handler)&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  41:&lt;/span&gt;             &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;( Type == &lt;span class="kwrd"&gt;null&lt;/span&gt; )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  42:&lt;/span&gt;             {
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  43:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  44:&lt;/span&gt;                 &lt;span class="rem"&gt;//### loop through all other RedirectToUrlOnErrorAttribute on this method&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  45:&lt;/span&gt;                 &lt;span class="kwrd"&gt;foreach&lt;/span&gt;( RedirectOnErrorAttribute att &lt;span class="kwrd"&gt;in&lt;/span&gt; GetAllAttributes( filterContext ) )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  46:&lt;/span&gt;                     &lt;span class="rem"&gt;//### ignore self&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  47:&lt;/span&gt;                     &lt;span class="kwrd"&gt;if&lt;/span&gt;( att.GetHashCode() == &lt;span class="kwrd"&gt;this&lt;/span&gt;.GetHashCode() )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  48:&lt;/span&gt;                         &lt;span class="kwrd"&gt;continue&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  49:&lt;/span&gt;                     &lt;span class="rem"&gt;//### if another catch-all attribute is found, throw an exception&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  50:&lt;/span&gt;                     &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;( att.Type == &lt;span class="kwrd"&gt;null&lt;/span&gt; )
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  51:&lt;/span&gt;                         &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentException( &lt;span class="str"&gt;&amp;quot;Only one RedirectOnErrorAttribute per Action may be specified without its Type property provided.&amp;quot;&lt;/span&gt; );
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  52:&lt;/span&gt;                     &lt;span class="rem"&gt;//### if an exact match is found, stop processing the catch-all. that attribute has priority&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  53:&lt;/span&gt;                     &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;( att.IsExactMatch(ex) )
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  54:&lt;/span&gt;                         &lt;span class="kwrd"&gt;return&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  55:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  56:&lt;/span&gt;                 &lt;span class="rem"&gt;//### no exact matches were found. if the specified Type for the catch-all fits, process here&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  57:&lt;/span&gt;                 Redirect(filterContext);
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  58:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  59:&lt;/span&gt;             }
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  60:&lt;/span&gt;             &lt;span class="kwrd"&gt;else&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  61:&lt;/span&gt;                 &lt;span class="rem"&gt;//### specified Type was not null, but did not match the thrown exception. don&amp;#39;t process&lt;/span&gt;
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  62:&lt;/span&gt;                 &lt;span class="kwrd"&gt;return&lt;/span&gt;;
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  63:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  64:&lt;/span&gt;         }
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  65:&lt;/span&gt;&amp;nbsp; 
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  66:&lt;/span&gt;         &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsExactMatch( Exception exception )
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  67:&lt;/span&gt;         {
&lt;/pre&gt;
&lt;pre class="alteven"&gt;
&lt;span class="lnum"&gt;  68:&lt;/span&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt;( Type != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; exception.GetType() == Type )
&lt;/pre&gt;
&lt;pre class="alt"&gt;
&lt;span class="lnum"&gt;  69:&lt;/span&gt;                 &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"