<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://james.newtonking.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>James Newton-King : ASP.NET</title><link>http://james.newtonking.com/archive/tags/ASP.NET/default.aspx</link><description>Tags: ASP.NET</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>Speeding up ASP.NET with the Runtime Page Optimizer</title><link>http://james.newtonking.com/archive/2008/10/19/speeding-up-asp-net-with-the-runtime-page-optimizer.aspx</link><pubDate>Sun, 19 Oct 2008 04:40:00 GMT</pubDate><guid isPermaLink="false">bce7ef4a-1ab4-4a64-ae34-bb54d1362c7e:31382</guid><dc:creator>James Newton-King</dc:creator><slash:comments>115</slash:comments><comments>http://james.newtonking.com/archive/2008/10/19/speeding-up-asp-net-with-the-runtime-page-optimizer.aspx#comments</comments><description>&lt;p&gt;&lt;img src="http://james.newtonking.com/images/SpeedupthewebwithRuntimePageOptimizer_AA6A/rpo_brand_smaller_white_bg.png" style="border-width: 0px; display: inline;" title="I am sick of running away. Did 'brave heart' run away? Did 'payback' run away?" alt="I am sick of running away. Did 'brave heart' run away? Did 'payback' run away?" mce_src="http://james.newtonking.com/images/SpeedupthewebwithRuntimePageOptimizer_AA6A/rpo_brand_smaller_white_bg.png" width="245" border="0" height="68"&gt; &lt;/p&gt;  &lt;p&gt;Earlier this year I worked on an exciting product called the &lt;a href="http://www.getrpo.com" mce_href="http://www.getrpo.com" target="_blank"&gt;Runtime Page Optimizer&lt;/a&gt; (RPO). Originally written by the guys at &lt;a href="http://www.actionthis.com/" mce_href="http://www.actionthis.com/" target="_blank"&gt;ActionThis&lt;/a&gt; to solve their website’s performance issues, I had the opportunity to develop it with them and help turn the RPO into a product that works on any ASP.NET website.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;How RPO works&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;At its heart the RPO is a &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.ihttpmodule.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.web.ihttpmodule.aspx" target="_blank"&gt;HttpModule&lt;/a&gt; that intercepts page content at runtime, inspects it, and then rewrites the page so that is optimized to be downloaded to the client. Because the RPO is a module it can quickly be added to any existing ASP.NET website, creating instant performance improvements.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;What RPO optimizes&lt;/b&gt;&lt;/p&gt;  &lt;p&gt;&lt;img src="http://james.newtonking.com/images/SpeedupthewebwithRuntimePageOptimizer_AA6A/beforegraph.gif" style="margin: 0px 0px 5px 5px; display: inline;" title="A gun is not a weapon Marge, it's a tool. Like a butcher knife, or a harpoon, or... or an alligator." alt="A gun is not a weapon Marge, it's a tool. Like a butcher knife, or a harpoon, or... or an alligator." mce_src="http://james.newtonking.com/images/SpeedupthewebwithRuntimePageOptimizer_AA6A/beforegraph.gif" width="280" align="right" border="0" height="180"&gt;The RPO does three things to speed up a web page:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;b&gt;Reduces HTTP requests&lt;/b&gt;&amp;nbsp; &lt;br&gt;Reducing the number of resources on a page often produces the most dramatic improvement in performance. A modest sized web page can still take a significant amount of time to load if it contains many stylesheets, scripts and image files.       &lt;br&gt;The reason for this is most of the time spent waiting for a web page to load is not for large files to download but from &lt;a href="http://yuiblog.com/blog/2006/11/28/performance-research-part-1/" mce_href="http://yuiblog.com/blog/2006/11/28/performance-research-part-1/" target="_blank"&gt;HTTP requests bouncing between the browser and the server&lt;/a&gt;. The RPO fixes this by intelligently combining CSS and JavaScript text files together and merging images through &lt;a href="http://websiteoptimization.com/speed/tweak/css-sprites/" mce_href="http://websiteoptimization.com/speed/tweak/css-sprites/" target="_blank"&gt;CSS spriting&lt;/a&gt;. Fewer resources means less time wasted from HTTP requests and faster page loads. &lt;/li&gt; &lt;/ul&gt;  &lt;ul&gt;   &lt;li&gt;&lt;b&gt;Compresses Content&lt;/b&gt;       &lt;br&gt;RPO minifies (whitespace removal) and zip compresses JavaScript and CSS files, as well as the ASP.NET page itself. Compression reduces page size, saves bandwidth and further decreasing page load times. &lt;/li&gt; &lt;/ul&gt;  &lt;ul&gt;   &lt;li&gt;&lt;b&gt;Caching&lt;/b&gt;       &lt;br&gt;The RPO ensures all static content has the correct HTTP headers to be cached on a user’s browser. This further decreases "warm" page load times and saves even more bandwidth. When resources change on the server, the client-side cache is automatically refreshed. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;b&gt;&lt;img src="http://james.newtonking.com/images/SpeedupthewebwithRuntimePageOptimizer_AA6A/aftergraph.gif" style="margin: 0px 0px 5px 5px; display: inline;" title="If you really want something in life you have to work for it. Now quiet, they're about to announce the lottery numbers." alt="If you really want something in life you have to work for it. Now quiet, they're about to announce the lottery numbers." mce_src="http://james.newtonking.com/images/SpeedupthewebwithRuntimePageOptimizer_AA6A/aftergraph.gif" width="280" align="right" border="0" height="179"&gt;Other stuff&lt;/b&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Every site is different so the RPO has &lt;a href="http://www.getrpo.com/Product/HowItWorks/" mce_href="http://www.getrpo.com/Product/HowItWorks/" target="_blank"&gt;extensive configuration options&lt;/a&gt; to customize it to best optimize your ASP.NET application. RPO has been used on ASP.NET AJAX, MVC, SharePoint, CRM, EpiServer and DotNetNuke websites. &lt;/li&gt;    &lt;li&gt;Lots of thought has been put into performance. The RPO caches all combined content and supports load balancing. Once combined content has been cached the only thing that happens at runtime is lightweight parsing of HTML, which is darn quick. I know because I wrote it that way &lt;img src="http://james.newtonking.com/emoticons/emotion-1.gif" alt="Smile" /&gt; &lt;/li&gt;    &lt;li&gt;The RPO supports all browsers, including new kid on the block: Chrome. RPO is even smart enough to &lt;a href="http://www.websiteoptimization.com/speed/tweak/inline-images/" mce_href="http://www.websiteoptimization.com/speed/tweak/inline-images/" target="_blank"&gt;take advantage of features only available in certain browsers&lt;/a&gt; and supply specially customized content to further improve page load times. &lt;/li&gt;    &lt;li&gt;The industrious people at RPO are making a version for Apache. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Working on the RPO was a great experience. Some very smart people are behind it and everyone contributed something unique to make RPO the awesome tool that it is today.&lt;/p&gt;  &lt;p&gt;RPO is out now and a fully featured trial is available at &lt;a href="http://www.getrpo.com/" mce_href="http://www.getrpo.com/" target="_blank"&gt;getrpo.com&lt;/a&gt;. Check it out!&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjames.newtonking.com%2farchive%2f2008%2f10%2f19%2fspeeding-up-asp-net-with-the-runtime-page-optimizer.aspx" mce_href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjames.newtonking.com%2farchive%2f2008%2f10%2f19%2fspeeding-up-asp-net-with-the-runtime-page-optimizer.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjames.newtonking.com%2farchive%2f2008%2f10%2f19%2fspeeding-up-asp-net-with-the-runtime-page-optimizer.aspx" alt="kick it on DotNetKicks.com" mce_src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjames.newtonking.com%2farchive%2f2008%2f10%2f19%2fspeeding-up-asp-net-with-the-runtime-page-optimizer.aspx" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt;&lt;/p&gt;&lt;p&gt;I noticed there is a &lt;a href="http://stackoverflow.com/questions/81108/runtime-page-optimizer-for-aspnet-any-comments" target="_blank" mce_href="http://stackoverflow.com/questions/81108/runtime-page-optimizer-for-aspnet-any-comments"&gt;question about the RPO on StackOverflow&lt;/a&gt; (I've been using StackOverflow a lot lately, excellent resource). The question discussion has some positive comments from users who have tried the RPO out. &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://james.newtonking.com/aggbug.aspx?PostID=31382" width="1" height="1"&gt;</description><category domain="http://james.newtonking.com/archive/tags/.NET/default.aspx">.NET</category><category domain="http://james.newtonking.com/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://james.newtonking.com/archive/tags/Intergen/default.aspx">Intergen</category></item><item><title>WebRequestDetailedErrorEvent</title><link>http://james.newtonking.com/archive/2006/08/10/WebRequestDetailedErrorEvent.aspx</link><pubDate>Thu, 10 Aug 2006 07:46:00 GMT</pubDate><guid isPermaLink="false">bce7ef4a-1ab4-4a64-ae34-bb54d1362c7e:744</guid><dc:creator>James Newton-King</dc:creator><slash:comments>67</slash:comments><comments>http://james.newtonking.com/archive/2006/08/10/WebRequestDetailedErrorEvent.aspx#comments</comments><description>&lt;b&gt;&lt;a onclick="if (typeof(urchinTracker) != 'undefined') urchinTracker('/downloads/detailederrorevent');" href="http://james.newtonking.com/downloads/detailederrorevent/detailederrorevent.zip" mce_href="http://james.newtonking.com/downloads/detailederrorevent/detailederrorevent.zip"&gt;Download DetailedErrorEvent&lt;/a&gt;&lt;/b&gt; - DetailedErrorEvent dll and C# source code&lt;br&gt;&lt;br&gt;One of the least talked about new ASP.NET 2.0 features, and one of my favorites, is the health monitoring system. Designed to help you monitor the status of a deployed website, the ASP.NET health monitoring system makes what could potentially be a chore easy. With just a few lines in your site’s web.config you can automatically log a variety of events to a file, a database or even send an email to an email address.&lt;br&gt;&lt;br&gt;While overall health monitoring it is a great new feature for ASP.NET, the WebRequestErrorEvent class provides disappointingly small amount of information. Raised when an unhandled exception is thrown during a web request, only basic information about the request that caused the error is provided such as the URL, the user host address and the authenticated user. Vital information like the request headers, form values, cookies and server variables are missing, making debugging the error more difficult than it needs to be.&lt;br&gt;&lt;br&gt;&lt;b&gt;WebRequestDetailedErrorEvent&lt;/b&gt;&lt;br&gt;&lt;br&gt;The WebRequestDetailedErrorEvent class inherits from WebRequestErrorEvent and includes the information that the base class is missing.&lt;br&gt;&lt;br&gt;One interesting aspect of the health monitoring events is that they are written asynchronously. While this allows them to be buffered and written without impacting performance, it also means that a copy of the request details need to be taken as HttpContext.Current will be null when the FormatCustomEventDetails method is called.&lt;br&gt;&lt;br&gt;&lt;div class="overflowpanel"&gt;&lt;div class="code" style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: Courier New;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Init(&lt;span style="color: teal;"&gt;Exception&lt;/span&gt; exception)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// FormatCustomEventDetails is called outside of a web request&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// need to take a copies of all the web request information to log&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: teal;"&gt;HttpContext&lt;/span&gt; context = &lt;span style="color: teal;"&gt;HttpContext&lt;/span&gt;.Current;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (context != &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: teal;"&gt;HttpRequest&lt;/span&gt; request = context.Request;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _cookies = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: teal;"&gt;HttpCookie&lt;/span&gt;[request.Cookies.Count];&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; request.Cookies.CopyTo(_cookies, 0);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _httpHeaders = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: teal;"&gt;NameValueCollection&lt;/span&gt;(request.Headers);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _form = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: teal;"&gt;NameValueCollection&lt;/span&gt;(request.Form);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _queryString = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: teal;"&gt;NameValueCollection&lt;/span&gt;(request.QueryString);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _serverVariables = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: teal;"&gt;NameValueCollection&lt;/span&gt;(request.ServerVariables);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _cookies = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: teal;"&gt;HttpCookie&lt;/span&gt;[0];&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _httpHeaders = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: teal;"&gt;NameValueCollection&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _form = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: teal;"&gt;NameValueCollection&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _queryString = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: teal;"&gt;NameValueCollection&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _serverVariables = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: teal;"&gt;NameValueCollection&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;&lt;b&gt;WebRequestDetailedErrorModule&lt;/b&gt;&lt;br&gt;&lt;br&gt;Unfortunately there is no seamless way to automatically raise the new web request error event instead old so a new HttpModule is required to do it for us. WebRequestDetailedErrorModule attaches a method to the Error event of the HttpApplication object and then raises WebRequestDetailedErrorEvent when a web request exception goes unhandled. Not all exceptions raised the default event so some logic is required to filter them out.&lt;br&gt;&lt;br&gt;&lt;div class="overflowpanel"&gt;&lt;div class="code" style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: Courier New;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; RaiseErrorEvent(&lt;span style="color: blue;"&gt;object&lt;/span&gt; sender, &lt;span style="color: teal;"&gt;EventArgs&lt;/span&gt; e)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: teal;"&gt;HttpApplication&lt;/span&gt; application = (&lt;span style="color: teal;"&gt;HttpApplication&lt;/span&gt;)sender;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: teal;"&gt;HttpContext&lt;/span&gt; context = application.Context;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: teal;"&gt;Exception&lt;/span&gt; exception = context.Error;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// unwrap exception if top exception is an HttpUnhandledException&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (exception &lt;span style="color: blue;"&gt;is&lt;/span&gt; &lt;span style="color: teal;"&gt;HttpUnhandledException&lt;/span&gt; &amp;amp;&amp;amp; exception.InnerException != &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; exception = exception.InnerException;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: teal;"&gt;HttpException&lt;/span&gt; httpException = exception &lt;span style="color: blue;"&gt;as&lt;/span&gt; &lt;span style="color: teal;"&gt;HttpException&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// don't log file not found exceptions&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (httpException != &lt;span style="color: blue;"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; httpException.GetHttpCode() == 404)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// viewstate exceptions raise a WebViewStateFailureAuditEvent, not an exception event&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (httpException != &lt;span style="color: blue;"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; httpException.InnerException &lt;span style="color: blue;"&gt;is&lt;/span&gt; &lt;span style="color: teal;"&gt;ViewStateException&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: teal;"&gt;WebBaseEvent&lt;/span&gt;.Raise(&lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: teal;"&gt;WebRequestDetailedErrorEvent&lt;/span&gt;(&lt;span style="color: maroon;"&gt;"An unhandled exception has occurred."&lt;/span&gt;, &lt;span style="color: blue;"&gt;this&lt;/span&gt;, &lt;span style="color: teal;"&gt;WebEventCodes&lt;/span&gt;.WebExtendedBase + 3005, 0, exception));&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;The old event will still be raised so if you may want to modify your web.config to not log events numbered 3005.&lt;br&gt;&lt;br&gt;&lt;b&gt;Usage&lt;/b&gt;&lt;br&gt;&lt;br&gt;To use the WebRequestDetailedErrorEvent simply add the module to your website’s httpModule section.&lt;br&gt;&lt;br&gt;&lt;div class="overflowpanel"&gt;&lt;div class="code" style="background: white none repeat scroll 0% 50%; font-size: 9pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: Courier New;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: maroon;"&gt;httpModules&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: maroon;"&gt;add&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;WebRequestDetailedErrorModule&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;Newtonsoft.DetailedErrorEvent.WebRequestDetailedErrorModule, Newtonsoft.DetailedErrorEvent&lt;/span&gt;"&lt;span style="color: blue;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: maroon;"&gt;httpModules&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;And that’s it. The new error event is now raised whenever an unhandled exception is thrown from a web request. Note that if you haven’t already setup ASP.NET to log health monitor events you can find out how &lt;a href="http://www.asp.net/QuickStart/aspnet/doc/monitoring/webevents.aspx" mce_href="http://www.asp.net/QuickStart/aspnet/doc/monitoring/webevents.aspx" target="_blank"&gt;here&lt;/a&gt;. &lt;br&gt;&lt;br&gt;&lt;b&gt;&lt;a onclick="if (typeof(urchinTracker) != 'undefined') urchinTracker('/downloads/detailederrorevent');" href="http://james.newtonking.com/downloads/detailederrorevent/detailederrorevent.zip" mce_href="http://james.newtonking.com/downloads/detailederrorevent/detailederrorevent.zip"&gt;Download DetailedErrorEvent&lt;/a&gt;&lt;/b&gt; - DetailedErrorEvent dll and C# source code&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://james.newtonking.com/aggbug.aspx?PostID=744" width="1" height="1"&gt;</description><category domain="http://james.newtonking.com/archive/tags/.NET/default.aspx">.NET</category><category domain="http://james.newtonking.com/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>WebDialog 1.1 released</title><link>http://james.newtonking.com/archive/2006/07/15/WebDialog-1.1-released.aspx</link><pubDate>Sat, 15 Jul 2006 00:21:00 GMT</pubDate><guid isPermaLink="false">bce7ef4a-1ab4-4a64-ae34-bb54d1362c7e:667</guid><dc:creator>James Newton-King</dc:creator><slash:comments>14</slash:comments><comments>http://james.newtonking.com/archive/2006/07/15/WebDialog-1.1-released.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://www.newtonsoft.com/downloads/#webdialog"&gt;WebDialog 1.1&lt;/a&gt; has been released.&lt;/p&gt;
&lt;p&gt;Much improved support for Atlas is the primary feature of this &lt;a href="http://www.newtonsoft.com/products/webdialog/"&gt;WebDialog&lt;/a&gt; release.&lt;/p&gt;
&lt;p&gt;What&amp;#39;s New:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New Feature - Improved Atlas support in Internet Explorer and Opera.&lt;/li&gt;
&lt;li&gt;Bug Fix - Fixed validators nested inside a dialog with client script enabled not displaying their error message when they failed.&lt;/li&gt;&lt;/ul&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://james.newtonking.com/aggbug.aspx?PostID=667" width="1" height="1"&gt;</description><category domain="http://james.newtonking.com/archive/tags/Newtonsoft/default.aspx">Newtonsoft</category><category domain="http://james.newtonking.com/archive/tags/.NET/default.aspx">.NET</category><category domain="http://james.newtonking.com/archive/tags/WebDialog/default.aspx">WebDialog</category><category domain="http://james.newtonking.com/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://james.newtonking.com/archive/tags/Business/default.aspx">Business</category></item><item><title>Preventing Spam With An ASP.NET CAPTCHA Control</title><link>http://james.newtonking.com/archive/2006/05/29/Preventing-Spam-With-An-ASP.NET-CAPTCHA-Control.aspx</link><pubDate>Mon, 29 May 2006 09:34:00 GMT</pubDate><guid isPermaLink="false">bce7ef4a-1ab4-4a64-ae34-bb54d1362c7e:283</guid><dc:creator>James Newton-King</dc:creator><slash:comments>253</slash:comments><comments>http://james.newtonking.com/archive/2006/05/29/Preventing-Spam-With-An-ASP.NET-CAPTCHA-Control.aspx#comments</comments><description>The source and dll for the project can be downloaded here: &lt;a href="http://www.newtonsoft.com/downloads/captchacontrol/captchacontrol.zip"&gt;CaptchaControl.zip&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;
&lt;strong&gt;About&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;
A CAPTCHA image displays text that is readable to humans, but not to computers. The concept is useful because it provides a means to filter out automated programs while allowing real users to pass through. Bots for example, which spam comments on weblogs and other dynamic websites, are a fairly pervasive problem and even a regularly new and low traffic blog like this was getting dozens of spam comments every day. CAPTCHA is a means to stop them while still allowing real users to post.&lt;br /&gt;&lt;br /&gt;CaptchaControl is an ASP.NET server control that is designed to start working by just being dropping onto the page, without any modification. This version is based off &lt;a href="http://trefry.net/blogs/michael/archive/2005/05/11/182.aspx" target="_blank"&gt;Michael Trefry&amp;rsquo;s&lt;/a&gt; implementation, which is in turn based off &lt;a href="http://dbvt.com/blog/archive/2005/03/15/1433.aspx" target="_blank"&gt;Dan Burke&amp;rsquo;s&lt;/a&gt;. My update fixes a couple of issues around storing the code in a browser cookie and adds features like client validation. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;CatchaControl Overview&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The CaptchaControl class is a composite control and encapsulates the CAPTCHA image, a textbox for capturing the result and a validator for verifying the correct code was entered. It handles hooking all the controls together, pointing the image src towards the image handler and maintaining the state of the code, which is stored encrypted in a hidden form field and then decrypted on postback.&lt;br /&gt;&lt;br /&gt;
&lt;div class="overflowpanel"&gt;
&lt;div class="code" style="background:white none repeat scroll 0% 50%;font-size:10pt;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:black;font-family:Consolas;"&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="color:blue;"&gt;protected&lt;/span&gt; &lt;span style="color:blue;"&gt;override&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; OnPreRender(&lt;span style="color:teal;"&gt;EventArgs&lt;/span&gt; e)&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;base&lt;/span&gt;.OnPreRender(e);&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; RegenerateCode();&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Page.ClientScript.RegisterHiddenField(ClientID + &lt;span style="color:maroon;"&gt;&amp;quot;__hidden&amp;quot;&lt;/span&gt;, _encryptedCode);&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Page.RegisterRequiresPostBack(&lt;span style="color:blue;"&gt;this&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SetChildProperties();&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;}&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="color:blue;"&gt;bool&lt;/span&gt; &lt;span style="color:teal;"&gt;IPostBackDataHandler&lt;/span&gt;.LoadPostData(&lt;span style="color:blue;"&gt;string&lt;/span&gt; postDataKey, &lt;span style="color:teal;"&gt;NameValueCollection&lt;/span&gt; postCollection)&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; _encryptedCode = postCollection[ClientID + &lt;span style="color:maroon;"&gt;&amp;quot;__hidden&amp;quot;&lt;/span&gt;];&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; _code = &lt;span style="color:teal;"&gt;Encryptor&lt;/span&gt;.Decrypt(_encryptedCode, GetKey(), GetIV());&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;return&lt;/span&gt; &lt;span style="color:blue;"&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;&lt;br /&gt;CaptchaControl has a number of properties for modifying its behavior such as the text of the error message, whether to display for authenticated users and whether the code should be validated on the client with JavaScript (note that the unencrypted code will be included with the page if this is enabled). It also an optional LayoutTemplate property of ITemplate that allows the encapsulated controls layout to be customized.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Generating the CAPTCHA Image&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The CAPTCHA image is generated by CaptchaHandler, a HttpModule. Parameters in the querystring, including the encrypted code data, are passed to a class than handles generating the image, which is then rendered to the response. &lt;br /&gt;&lt;br /&gt;
&lt;div class="overflowpanel"&gt;
&lt;div class="code" style="background:white none repeat scroll 0% 50%;font-size:10pt;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:black;"&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="color:blue;"&gt;void&lt;/span&gt; &lt;span style="color:teal;"&gt;IHttpHandler&lt;/span&gt;.ProcessRequest(&lt;span style="color:teal;"&gt;HttpContext&lt;/span&gt; context)&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:teal;"&gt;HttpRequest&lt;/span&gt; request = context.Request;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:teal;"&gt;HttpResponse&lt;/span&gt; response = context.Response;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;string&lt;/span&gt; encryptedCode = request.QueryString[&lt;span style="color:maroon;"&gt;&amp;quot;code&amp;quot;&lt;/span&gt;];&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;string&lt;/span&gt; code = &lt;span style="color:teal;"&gt;Encryptor&lt;/span&gt;.Decrypt(encryptedCode, &lt;span style="color:teal;"&gt;CaptchaControl&lt;/span&gt;.GetKey(), &lt;span style="color:teal;"&gt;CaptchaControl&lt;/span&gt;.GetIV());&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;int&lt;/span&gt; width = &lt;span style="color:teal;"&gt;Convert&lt;/span&gt;.ToInt32(request.QueryString[&lt;span style="color:maroon;"&gt;&amp;quot;width&amp;quot;&lt;/span&gt;]);&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;int&lt;/span&gt; height = &lt;span style="color:teal;"&gt;Convert&lt;/span&gt;.ToInt32(request.QueryString[&lt;span style="color:maroon;"&gt;&amp;quot;height&amp;quot;&lt;/span&gt;]);&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:teal;"&gt;CaptchaImageGenerator&lt;/span&gt; captchaImage = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;CaptchaImageGenerator&lt;/span&gt;(code, width, height);&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; response.Clear();&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; response.ContentType = &lt;span style="color:maroon;"&gt;&amp;quot;img/jpeg&amp;quot;&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; response.Cache.SetCacheability(&lt;span style="color:teal;"&gt;HttpCacheability&lt;/span&gt;.NoCache);&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; captchaImage.RenderImage(response.OutputStream);&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;strong&gt;Usage&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Register the CaptchaHandler by adding the following to your web.config&amp;rsquo;s httpModule element. &lt;br /&gt;&lt;br /&gt;
&lt;div class="overflowpanel"&gt;
&lt;div class="code" style="background:white none repeat scroll 0% 50%;font-size:10pt;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:black;"&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:maroon;"&gt;add&lt;/span&gt;&lt;span style="color:blue;"&gt; &lt;/span&gt;&lt;span style="color:red;"&gt;verb&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;*&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt; &lt;/span&gt;&lt;span style="color:red;"&gt;path&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;captchahandler.axd&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt; &lt;/span&gt;&lt;span style="color:red;"&gt;type&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;Newtonsoft.CaptchaControl.CaptchaHandler, Newtonsoft.CaptchaControl&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;To add the CaptchaControl to a page simply place it where you want it to be displayed: &lt;br /&gt;&lt;br /&gt;
&lt;div class="overflowpanel"&gt;
&lt;div class="code" style="background:white none repeat scroll 0% 50%;font-size:10pt;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:black;"&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="background:yellow none repeat scroll 0% 50%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue;"&gt;@&lt;/span&gt; &lt;span style="color:maroon;"&gt;Register&lt;/span&gt; &lt;span style="color:red;"&gt;TagPrefix&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;ncc&amp;quot;&lt;/span&gt; &lt;span style="color:red;"&gt;Namespace&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;Newtonsoft.CaptchaControl&amp;quot;&lt;/span&gt; &lt;span style="color:red;"&gt;Assembly&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;Newtonsoft.CaptchaControl&amp;quot;&lt;/span&gt; &lt;span style="background:yellow none repeat scroll 0% 50%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;"&gt;%&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:maroon;"&gt;ncc&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:maroon;"&gt;CaptchaControl&lt;/span&gt; &lt;span style="color:red;"&gt;runat&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span style="color:red;"&gt;ID&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;CaptchaControl&amp;quot;&lt;/span&gt; &lt;span style="color:blue;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;The IsValid property on the page will automatically be set when the page&amp;rsquo;s validators, including CaptchaControl, are evaluated on postback.&lt;br /&gt;&lt;br /&gt;
&lt;div class="overflowpanel"&gt;
&lt;div class="code" style="background:white none repeat scroll 0% 50%;font-size:10pt;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:black;"&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="color:blue;"&gt;private&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; btnSubmit_Click(&lt;span style="color:blue;"&gt;object&lt;/span&gt; sender, &lt;span style="color:teal;"&gt;EventArgs&lt;/span&gt; e)&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:blue;"&gt;if&lt;/span&gt; (IsValid)&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:green;"&gt;// logic&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;The important question: Does it work? Since adding CAPTCHA validation to this blog comment spam has dropped from dozens each day to zero.&lt;br /&gt;&lt;br /&gt;The source and dll for the project can be downloaded here: &lt;a href="http://www.newtonsoft.com/downloads/captchacontrol/captchacontrol.zip"&gt;CaptchaControl.zip&lt;/a&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://james.newtonking.com/aggbug.aspx?PostID=283" width="1" height="1"&gt;</description><category domain="http://james.newtonking.com/archive/tags/.NET/default.aspx">.NET</category><category domain="http://james.newtonking.com/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>Logging JavaScript Errors To ASP.NET</title><link>http://james.newtonking.com/archive/2006/05/02/Logging-JavaScript-Errors-To-ASP.NET.aspx</link><pubDate>Tue, 02 May 2006 10:16:00 GMT</pubDate><guid isPermaLink="false">bce7ef4a-1ab4-4a64-ae34-bb54d1362c7e:98</guid><dc:creator>James Newton-King</dc:creator><slash:comments>80</slash:comments><comments>http://james.newtonking.com/archive/2006/05/02/Logging-JavaScript-Errors-To-ASP.NET.aspx#comments</comments><description>Over the past few years a huge jump in the complexity of JavaScript has occured on the browser, resulting in richer, more responsive and user friendly web applications. Unfortunatly this shift does not come without cost.&lt;br /&gt;&lt;br /&gt;Greater complexity on the client means more room for bugs, and without some effective means to log them you are left in the dark about problems until users are driven to complain.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Solution Overview&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The client exception logger comprises of three parts: a script on the client that catches the exceptions and sends them to the server, a HttpHandler on the server that receives the error details and logs them, and an ASP.NET control that links the two together.&lt;br /&gt;&lt;br /&gt;Details logged include the following:&lt;br /&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript exception message, line and file name
&lt;/li&gt;&lt;li&gt;Date and time 
&lt;/li&gt;&lt;li&gt;IP Address 
&lt;/li&gt;&lt;li&gt;User agent (browser and platform details)
&lt;/li&gt;&lt;li&gt;Session ID&lt;/li&gt;&lt;/ul&gt;&lt;strong&gt;Catching and Sending the Error on the Client &lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Whenever an exception is not caught in JavaScript it triggers an onerror event on the browser&amp;#39;s window object. It is comparable to ASP.NET&amp;rsquo;s Application_Error event in the global.asax.&lt;br /&gt;&lt;br /&gt;When the page is downloaded a ClientLogger object is created and a function is attached to the onerror event. That function calls a method on ClientLogger object which will send the error details to ASP.NET on the server using the XMLHttpRequest object. This is done asynchronously and does not effect the user.&lt;br /&gt;&lt;br /&gt;
&lt;div class="overflowpanel"&gt;
&lt;div class="code" style="background:white none repeat scroll 0% 50%;font-size:9pt;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:black;font-family:Courier New;"&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="color:blue;"&gt;var&lt;/span&gt; logger = &lt;span style="color:blue;"&gt;new&lt;/span&gt; ClientLogger({handlerUrl:&lt;span style="color:maroon;"&gt;&amp;#39;../../ClientLogger.axd&amp;#39;&lt;/span&gt;,sessionID:&lt;span style="color:maroon;"&gt;&amp;#39;2rnbawbkzuovsw55ymvflz45&amp;#39;&lt;/span&gt;});&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;window.onerror = &lt;span style="color:blue;"&gt;function&lt;/span&gt;(message, url, line) { logger.Log(message, url, line); };&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;strong&gt;Receiving and Logging the Error on the Server &lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;When sending the error data back to the server, rather than the page calling back to itself, the logger posts the details a custom HttpHandler. This is done to minimize side effects or performance issues of creating the page again.&lt;br /&gt;Note that the handler does not contain any logic for logging the error details. Instead it uses the new ASP.NET 2.0 Web Event feature, and raises a custom WebJavaScriptErrorEvent event.&lt;br /&gt;&lt;br /&gt;
&lt;div class="overflowpanel"&gt;
&lt;div class="code" style="background:white none repeat scroll 0% 50%;font-size:9pt;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:black;font-family:Courier New;"&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="color:teal;"&gt;WebBaseEvent&lt;/span&gt;.Raise(&lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;WebJavaScriptErrorEvent&lt;/span&gt;(jsMessage, &lt;span style="color:blue;"&gt;this&lt;/span&gt;, jsUrl, jsLine, pageUrl, userAgent, sessionID));&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;strong&gt;Packaging Everything Together in a Control &lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The ASP.NET control includes the JavaScript file (embedded in the dll) on the page and registers some JavaScript that creates the client object and attaches it to the onerror event. To enable JavaScript error logging include the control on your master page:&lt;br /&gt;&lt;br /&gt;
&lt;div class="overflowpanel"&gt;
&lt;div class="code" style="background:white none repeat scroll 0% 50%;font-size:9pt;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:black;font-family:Courier New;"&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="background:yellow none repeat scroll 0% 50%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:blue;"&gt;@&lt;/span&gt; &lt;span style="color:maroon;"&gt;Register&lt;/span&gt; &lt;span style="color:red;"&gt;TagPrefix&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;ncl&amp;quot;&lt;/span&gt; &lt;span style="color:red;"&gt;Namespace&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;Newtonsoft.ClientLogger&amp;quot;&lt;/span&gt; &lt;span style="color:red;"&gt;Assembly&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;Newtonsoft.ClientLogger&amp;quot;&lt;/span&gt; &lt;span style="background:yellow none repeat scroll 0% 50%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;"&gt;%&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="color:blue;"&gt;&lt;br /&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:maroon;"&gt;ncl&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:maroon;"&gt;ClientLogger&lt;/span&gt; &lt;span style="color:red;"&gt;runat&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span style="color:blue;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;And register the HttpHandler in the web.config:&lt;br /&gt;&lt;br /&gt;
&lt;div class="overflowpanel"&gt;
&lt;div class="code" style="background:white none repeat scroll 0% 50%;font-size:9pt;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:black;font-family:Courier New;"&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:maroon;"&gt;add&lt;/span&gt;&lt;span style="color:blue;"&gt; &lt;/span&gt;&lt;span style="color:red;"&gt;verb&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;*&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt; &lt;/span&gt;&lt;span style="color:red;"&gt;path&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;clientlogger.axd&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt; &lt;/span&gt;&lt;span style="color:red;"&gt;type&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;Newtonsoft.ClientLogger.ClientLoggerHandler, Newtonsoft.ClientLogger&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;strong&gt;Consuming The Web Event&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The great thing about ASP.NET Web Events is that you can decide how you want to log the event, and it is simple as modifying your web application&amp;#39;s web.config file. For example in just a few lines you can configure ASP.NET to log all errors to your database or send them to an email address. The rule below for example will log all errors to the database. You can learn more about using ASP.NET Web Events &lt;a href="http://www.asp.net/QuickStart/aspnet/doc/monitoring/webevents.aspx"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;
&lt;div class="overflowpanel"&gt;
&lt;div class="code" style="background:white none repeat scroll 0% 50%;font-size:9pt;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:black;font-family:Courier New;"&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:maroon;"&gt;add&lt;/span&gt;&lt;span style="color:blue;"&gt; &lt;/span&gt;&lt;span style="color:red;"&gt;name&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;SqlServerWebErrorLogger&lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:red;"&gt;eventName&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;All Errors&lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="margin:0px;"&gt;&lt;span style="color:blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color:red;"&gt;provider&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;SqlWebEventProvider&lt;/span&gt;&amp;quot;&lt;span style="color:blue;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;And that&amp;#39;s it. You will now know about JavaScript errors as they happen.&lt;br /&gt;&lt;br /&gt;The source and dll for the project can be downloaded here: &lt;a href="http://www.newtonsoft.com/downloads/clientlogger/clientlogger.zip"&gt;ClientLogger.zip&lt;/a&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://james.newtonking.com/aggbug.aspx?PostID=98" width="1" height="1"&gt;</description><category domain="http://james.newtonking.com/archive/tags/.NET/default.aspx">.NET</category><category domain="http://james.newtonking.com/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item></channel></rss>