<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Bill Rowell &#187; ASP.NET</title>
	<atom:link href="http://www.billrowell.com/category/development/web-development/aspnet/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.billrowell.com</link>
	<description>Rumblings of Code,  and Then Some...</description>
	<lastBuildDate>Thu, 02 Feb 2012 00:08:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>SqlCacheDependency and Query Notifications</title>
		<link>http://www.billrowell.com/2011/11/19/sqlcachedependency-and-query-notifications/</link>
		<comments>http://www.billrowell.com/2011/11/19/sqlcachedependency-and-query-notifications/#comments</comments>
		<pubDate>Sat, 19 Nov 2011 21:22:20 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.billrowell.com/?p=1007</guid>
		<description><![CDATA[There&#8217;s a lot of scattered information out there on how to configure ASP.NET applications to leverage Microsoft SQL Server&#8217;s Query Notification and Service Broker services for caching in ASP.NET applications. The two best step by step tutorials I&#8217;ve found online are: http://www.simple-talk.com/sql/t-sql-programming/using-and-monitoring-sql-2005-query-notification/ http://dimarzionist.wordpress.com/2009/04/01/how-to-make-sql-server-notifications-work/ Both of those articles should get you started for sure. I ran [...]]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s a lot of scattered information out there on how to configure ASP.NET applications to leverage Microsoft SQL Server&#8217;s Query Notification and Service Broker services for caching in ASP.NET applications.  The two best step by step tutorials I&#8217;ve found online are:</p>
<p><a href="http://www.simple-talk.com/sql/t-sql-programming/using-and-monitoring-sql-2005-query-notification/">http://www.simple-talk.com/sql/t-sql-programming/using-and-monitoring-sql-2005-query-notification/</a></p>
<p><a href="http://dimarzionist.wordpress.com/2009/04/01/how-to-make-sql-server-notifications-work/">http://dimarzionist.wordpress.com/2009/04/01/how-to-make-sql-server-notifications-work/</a></p>
<p>Both of those articles should get you started for sure.  I ran into issues keeping our application from crashing after a period of time though while leveraging Query Notifications for caching in a few of my sites.  The biggest issue I found was that I would see the following exception in our logs:</p>
<div class="wp_syntax">
<div class="code">
<pre class="csharp charp">
When using SqlDependency without providing an options value, SqlDependency.Start() <br/>must be called prior to execution of a command added to the SqlDependency instance.</pre>
</div>
</div>
<p>Never did quite get a handle on what was going on here.  I did figure out though that I could always find this in my Application log around the time that exception was thrown:</p>
<div class="wp_syntax">
<div class="code">
<pre class="csharp charp">
The query notification dialog on conversation handle '{A1FB449B-DEB3-E011-B6D2-002590198D55}.' closed due to the following error: '<?xml version="1.0"?><Error xmlns="http://schemas.microsoft.com/SQL/ServiceBroker/Error"><Code>-8470</Code><Description>Remote service has been dropped.</Description></Error>'.
</pre>
</div>
</div>
<p>So, does this mean that I called SqlDependency.Stop() and now queued notifications aren&#8217;t going to be delivered.  Are these critical errors that keep the application from coming back?  I&#8217;ve read that a lot of the Query Notification messages you see in the log aren&#8217;t critical errors and can be ignored.  I can&#8217;t ignore the timing of this error and the exception being thrown above though.</p>
<p>Anyway, I finally decided to pull this stuff out of our application until I get a better handle on what&#8217;s going on.  The last straw was that I was trying to sync some database changes during a maintenance period and I couldn&#8217;t get them to sync because of a bunch of these SQL Query Notification issues.  As I write this, I can&#8217;t even get my database back online as I&#8217;m waiting for ALTER DATABASE SET SINGLE_USER to complete (approaching 3 hours!!!).  As I keep waiting, my Application log keeps filling up with the following Query Notification messages:</p>
<p><strong>Query notification delivery could not send message on dialog &#8216;{FE161F6A-D6B3-E011-B6D2-002590198D55}.&#8217;. Delivery failed for notification &#8216;﻿<qn:QueryNotification xmlns:qn="http://schemas.microsoft.com/SQL/Notifications/QueryNotification" id="1530017" type="change" source="database" info="restart" database_id="5" sid="0x1F59122ACF8727448DA988D041A1D484"><qn:Message>85addbaa-ce66-431d-870f-d91580a7480a;d527d584-9fd4-4b13-85bc-87cb6c2e166f</qn:Message></qn:QueryNotification>&#8216; because of the following error in service broker: &#8216;The conversation handle &#8220;FE161F6A-D6B3-E011-B6D2-002590198D55&#8243; is not found.&#8217;.<br/><br />
For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.</strong></p>
<p>I had a response to a post I made on the ASP.NET Forum and it was suggested that with all the cached items in the system, that SQL Server really could not catch up.  This is a problem because not only does it slow the entire system down, but when you have to cycle the SQL Server service itself, it takes forever for the system to come back up because all of the notifications get requeued or something.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.billrowell.com/2011/11/19/sqlcachedependency-and-query-notifications/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Website Speed &amp; Performance Tuning with GTmetrix</title>
		<link>http://www.billrowell.com/2011/03/21/website-speed-performance-tuning-with-gtmetrix/</link>
		<comments>http://www.billrowell.com/2011/03/21/website-speed-performance-tuning-with-gtmetrix/#comments</comments>
		<pubDate>Tue, 22 Mar 2011 04:48:45 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.billrowell.com/?p=875</guid>
		<description><![CDATA[I stumbled upon a little gem today while searching for a few more techniques to improve the performance of my ASP.NET web applications. I use YSlow and Google Page Speed almost daily, and it was great to find this website that combines the both of them called GTmetrix. GTmetrix combines both Google Page Speed and [...]]]></description>
			<content:encoded><![CDATA[<p>I stumbled upon a little gem today while searching for a few more techniques to improve the performance of my ASP.NET web applications.  I use YSlow and Google Page Speed almost daily, and it was great to find this website that combines the both of them called <a href="http://gtmetrix.com/">GTmetrix</a>.  GTmetrix combines both Google Page Speed and YSlow into an easy to read, tabbed, table of recommendations.  Each recommendation, once expanded, offers you a list of tasks that you can complete to improve the performance of your test.  What&#8217;s more, is it ranks the grouping of recommendations from Low to High so that you know what to get after first.  If you&#8217;re serious about your web site&#8217;s performance, definitely check this one out!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.billrowell.com/2011/03/21/website-speed-performance-tuning-with-gtmetrix/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ASP.NET SQLCacheDependency with SQL Query Notifications</title>
		<link>http://www.billrowell.com/2010/09/23/asp-net-sqlcachedependency-with-sql-query-notifications/</link>
		<comments>http://www.billrowell.com/2010/09/23/asp-net-sqlcachedependency-with-sql-query-notifications/#comments</comments>
		<pubDate>Thu, 23 Sep 2010 13:28:11 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.billrowell.com/?p=659</guid>
		<description><![CDATA[I&#8217;m going to make this quick and dirty. I&#8217;ve set up my ASP.NET web applications to leverage SQLCacheDependency with SQL Server 2005 Query Notifications. The setup process takes a some time and debugging can be tricky. But the payoff can be enormous. The bottom line is that the performance increase on page load times is [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m going to make this quick and dirty.  I&#8217;ve set up my ASP.NET web applications to leverage SQLCacheDependency with SQL Server 2005 Query Notifications.  The setup process takes a some time and debugging can be tricky.  But the payoff can be enormous.  The bottom line is that the performance increase on page load times is well worth the effort, especially for data that doesn&#8217;t change all that often.  I found it really useful for caching product data on my eCommerce sites, especially as the number of products in the system grew to over 5,000.  However, I always seem to miss a step when when configuring my SQL Server 2005 databases; so this post is for my own reference, but if it helps someone else out there, even better.</p>
<p>The original article I used as a basis for configuring my applications is at the url below:</p>
<p><a href="http://www.simple-talk.com/sql/t-sql-programming/using-and-monitoring-sql-2005-query-notification/">http://www.simple-talk.com/sql/t-sql-programming/using-and-monitoring-sql-2005-query-notification/</a></p>
<p>Follow the steps there and you&#8217;re good to go.  Especially use the SQL Profiler debug steps at the bottom of the article if you get tripped up.  One thing that I always had to do with my databases to get everything to work properly was execute the following query:</p>
<div class="wp_syntax">
<div class="code">
</div>
<pre class="csharp csharp">
use &lt;dbname&gt;
EXEC dbo.sp_changedbowner @loginame = N'&lt;dbuser&gt;', @map = false
</pre>
</div>
<p>Make sure you use this caching technique responsible though.  The Query Notifications can use up processing power so only cache data that you know will give your application a performance bump.  Also beware of memory usage as you cache more and more data.  You could end up caching so much data your application needs to restart often and that could cause slow page load times.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.billrowell.com/2010/09/23/asp-net-sqlcachedependency-with-sql-query-notifications/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Easily Cause StackOverflow Exception in ASP.NET Web Application</title>
		<link>http://www.billrowell.com/2010/03/19/easily-cause-stackoverflow-exception-in-asp-net-web-application/</link>
		<comments>http://www.billrowell.com/2010/03/19/easily-cause-stackoverflow-exception-in-asp-net-web-application/#comments</comments>
		<pubDate>Fri, 19 Mar 2010 18:27:44 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.billrowell.com/?p=657</guid>
		<description><![CDATA[This is a short one, but since I can&#8217;t believe I&#8217;ve never managed to do this before, I thought I&#8217;d post a little tidbit on it. I threw a StackOverflow in one of my ASP.NET C# web applications today. Watching the request keep going for about 5 minutes, I checked the Event Log on the [...]]]></description>
			<content:encoded><![CDATA[<p>This is a short one, but since I can&#8217;t believe I&#8217;ve never managed to do this before, I thought I&#8217;d post a little tidbit on it.  I threw a StackOverflow in one of my ASP.NET C# web applications today.  Watching the request keep going for about 5 minutes, I checked the Event Log on the server.  There it was, StackOverflow exception.  Say, what?</p>
<p>How did I manage it?  Recursively add a control to its own control collection.  The .NET framework just freaks and the application pool just gets restarted after each exception kills the app.  Glad it didn&#8217;t take long to figure it out!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.billrowell.com/2010/03/19/easily-cause-stackoverflow-exception-in-asp-net-web-application/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Remove ViewState From ASP.NET Page to Improve Performance</title>
		<link>http://www.billrowell.com/2009/06/17/remove-viewstate-from-asp-net-page-to-improve-performance/</link>
		<comments>http://www.billrowell.com/2009/06/17/remove-viewstate-from-asp-net-page-to-improve-performance/#comments</comments>
		<pubDate>Thu, 18 Jun 2009 00:21:41 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://www.billrowell.com/?p=526</guid>
		<description><![CDATA[In a previous post, I eluded to the fact that I remove the ViewState from our ASP.NET pages to improve performance. I can&#8217;t take credit for coming up with the idea though. Originally, I got the idea and solution I wanted to implement by reading this article at EggHead Cafe. The solution I chose was [...]]]></description>
			<content:encoded><![CDATA[<p>In a previous post, I eluded to the fact that I remove the ViewState from our ASP.NET pages to improve performance.  I can&#8217;t take credit for coming up with the idea though.  Originally, I got the idea and solution I wanted to implement by reading <a href="http://www.eggheadcafe.com/articles/20040613.asp">this article at EggHead Cafe</a>.  The solution I chose was to store the ViewState on the web server&#8217;s file system and reference the file in the page sent back to the client.  I&#8217;ll outline how I did that below.</p>
<p>The first thing you&#8217;ll want to do is create a new Page base class that inherits from System.Web.UI.Page so you can override some of its methods, namely SavePageStateToPersistenceMedium and LoadPageStateFromPersistenceMedium.  This will allow you to save the page&#8217;s ViewState to the file system and then re-load it on a post back.  Let&#8217;s start with saving the ViewState to the file system.</p>
<div class="wp_syntax">
<div class="code">
<pre class="csharp csharp">
protected override void protectedSavePageStateToPersistenceMedium(object viewState)
{
	// Serialize the view state into a base-64 encoded string
        LosFormatter los = new LosFormatter();
	StringWriter writer = new StringWriter();
	los.Serialize(writer, viewState);

	string guid = NewGuid();
	string vsp = ViewStateFilePath(guid);

	// Save the string to disk
	StreamWriter sw = File.CreateText(vsp);
	sw.Write(writer.ToString());
	sw.Close();

	// Save the guid in a form field
	ClientScript.RegisterHiddenField("__VIEWSTATE_GUID", guid);
}
</pre>
</div>
</div>
<p>So, let&#8217;s step through what we&#8217;re doing here.  The first few lines of code, we&#8217;re serializing the view state.  Next, where we call</p>
<div class="wp_syntax">
<div class="code">
<pre class="csharp csharp">
string uid = NewGuid();
</pre>
</div>
</div>
<p>We&#8217;re creating a new guid that we will use in creating the file name on the server for the actual value of the current view state.  NewGuid() just returns a new guid value from the System.Guid class.</p>
<p>Next, we need to create a path to where we&#8217;re going to store the file as well as its file name.  Now, you can do this any way you want as long as all of your files end up being unique.  You can&#8217;t go overwriting one guy&#8217;s view state with someone else&#8217;s.  Now I based mine on basically the guid appended with the current request path minus the extension and replacing the slashes with dashes.  So, my filename looks like:</p>
<div class="wp_syntax">
<div class="code">
<pre class="csharp csharp">
string fileName = guid + "-" + Path.GetFileNameWithoutExtension(Request.Path).Replace(
    "/", "-") + ".vs";
</pre>
</div>
</div>
<p>Where the guid was passed in to the function that I called to create the view state file path.</p>
<p>So now that we have a path to where we can write the file, we can go ahead and do so using the StreamWriter that we created.  Now, the last thing to do is spit out where we can find the view state to the client.  This is done by registering a hidden field with the client:</p>
<div class="wp_syntax">
<div class="code">
<pre class="csharp csharp">
ClientScript.RegisterHiddenField("__VIEWSTATE_GUID", guid);
</pre>
</div>
</div>
<p>That GUID allows you to recall the proper file for the client when you need to access the ViewState.</p>
<p>So now you&#8217;ve persisted the view state to the file system.  Now all that&#8217;s left is to load it up when needed, which is done with LoadPageStateFromPersistenceMedium(), which is below.</p>
<div class="wp_syntax">
<div class="code">
<pre class="csharp csharp">
protected override object LoadPageStateFromPersistenceMedium()
{
	string guid = Request.Form["__VIEWSTATE_GUID"];
	if (guid == "")
		return null;
		// determine the file to access
	if (!File.Exists(ViewStateFilePath(guid)))
	{
		return null;
	}
	else
	{
		// open the file
		StreamReader sr = File.OpenText(ViewStateFilePath(guid));
		string viewStateString = sr.ReadToEnd();
		sr.Close();
		// deserialize the string
		LosFormatter los = new LosFormatter();
		return los.Deserialize(viewStateString);
	}
}
</pre>
</div>
</div>
<p>This approach gives you the ability to minimize the amount of data that you have to send over the wire to a client browser.  There are other solutions to this like storing the ViewState in memory, but I felt that it was a waste of resources if a ViewState might only be used once and then abandoned.  The one thing you&#8217;ll want to do is manage your saved ViewState files on your disk.  These files can get out of control, especially when you get a lot of visitor&#8217;s.  So what I did was just set up a Scheduled Task in Windows to clean up stored ViewState&#8217;s every three hours.  This works out pretty good since a ViewState really won&#8217;t be needed beyond that timeframe.</p>
<p>Anyway, I hope this solution helps some other C# ASP.NET developers out there.  It sure worked out great for me!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.billrowell.com/2009/06/17/remove-viewstate-from-asp-net-page-to-improve-performance/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ASP.NET Site whitehouse.gov Reviewed</title>
		<link>http://www.billrowell.com/2009/01/21/aspnet-site-whitehousegov-reviewed/</link>
		<comments>http://www.billrowell.com/2009/01/21/aspnet-site-whitehousegov-reviewed/#comments</comments>
		<pubDate>Wed, 21 Jan 2009 15:05:44 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.billrowell.com/?p=514</guid>
		<description><![CDATA[So I was over on Slashdot last night looking for something interesting to read and ran across this tidbit about the new whitehouse.gov site that runs on ASP.NET. Honestly I think the only reason this got mentioned on Slashdot is that yesterday was Inauguration Day. Any other day and it probably would have fallen through [...]]]></description>
			<content:encoded><![CDATA[<p>So I was over on <a href="http://slashdot.org/">Slashdot</a> last night looking for something interesting to read and ran across this <a href="http://dotnetperls.com/Content/whitehouse-gov-Site.aspx">tidbit</a> about the new <a href="http://whitehouse.gov">whitehouse.gov</a> site that runs on ASP.NET.  Honestly I think the only reason this got mentioned on Slashdot is that yesterday was Inauguration Day.  Any other day and it probably would have fallen through the cracks.  Anyway, I decided to take a look at the pointers that the author brought up to see if there was something I could learn.  Most of the improvements I already knew about, but there were a couple that were new to me.  Two that I&#8217;d like to consider implementing in my sites are:</p>
<ul>
<li>Remove X-Aspnet-Version: header (remove 30 bytes per request)</li>
<li>Use compressed JQuery from Google&#8217;s servers (lower latency and improve performance)</li>
</ul>
<p>The one issue with using JQuery from Google is your tied to whatever they&#8217;re using.  If a newer version comes out and you want to use it but Google doesn&#8217;t, you couldn&#8217;t do this.  Luckily I use JQuery 1.2.6, so this isn&#8217;t an issue for me.</p>
<p>As for the author&#8217;s review, I thought it was pretty good.  A real world example is always a great illustration of what to do and what not to do.  I&#8217;d have liked to see him make a suggestion on how to fix one of the issues he found, the ViewState issue, which would have been useful for other developers making the same mistake.</p>
<p>ViewState is still necessary for an ASP.NET application, however you don&#8217;t have to pass the entire ViewState back to the client.  Its a waste of bandwidth (and can &#8217;cause some nasty Base64 exceptions).  One solution I use is to store the ViewState on the file system and only pass the file name back to the client for reference later on.  It takes up a lot less bandwidth than a potentially <strong>huge</strong> ViewState.  Other solutions are storing it in memory, the database, or by some other means.  We clean out our old ViewState&#8217;s every 3-4 hours as many of them aren&#8217;t needed after that point (I&#8217;m thinking this might make a good article in the future).</p>
<p>Another example that kind of irked me was the site&#8217;s use of meta keywords.  Uhm, yeah, this might not be as relevant anymore for Search Engine Optimization, but its still not a <strong>bad</strong> thing to have it in there.  Just keep it to 200-300 characters.  Nothing too crazy.</p>
<p>One last thing that he pointed out that I just didn&#8217;t agree with was that the server was running IIS6.0.  Now, correct me if I&#8217;m wrong, but IIS7.0 is only supported on Windows Server 2008, right?  Well, IT departments have budgets and all, so maybe a Windows Server 2008 license or the hardware to install it to wasn&#8217;t available?  I know in my case, the budget doesn&#8217;t always allow for the latest and greatest, even if I want to use it.  So to knock the development team for using IIS6.0 seems a little over the top if you ask me.</p>
<p>This entire site could definitely use some improvements, which the article nicely points out.  To go one step further, I suggest any web developer install YSlow for Firebug for the Firefox browser.  This came in handy for me when I was trying to optimize my sites.  The whitehouse.gov site&#8217;s YSlow score is a 51 (an F), which is horrible.  <a href="http://www.billrowell.com/2008/11/21/speeding-up-your-web-site-with-yslow-for-firebug/">When I started using YSlow</a>, I noticed some of my sites had a similar score, to which I was appalled and went to fixing pronto.  By implementing some of the changes that I could as suggested by YSlow, I got us up to a 78, which is a high C.  Some changes you can&#8217;t make (like Javascript at the bottom of pages and using a Content Delivery Network) due to how your application works and changing them just to make a minor improvement is more trouble than its worth.  However, there isn&#8217;t any excuse to have an ASP.NET site that scores so low.  Those folks over at whitehouse.gov definitely need to clean things up!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.billrowell.com/2009/01/21/aspnet-site-whitehousegov-reviewed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>URL Rewriting in ASP.NET &#8211; ISAPI Rewrite vs. UrlRewritingNet</title>
		<link>http://www.billrowell.com/2009/01/20/url-rewriting-in-aspnet-isapi-rewrite-vs-urlrewritingnet/</link>
		<comments>http://www.billrowell.com/2009/01/20/url-rewriting-in-aspnet-isapi-rewrite-vs-urlrewritingnet/#comments</comments>
		<pubDate>Wed, 21 Jan 2009 03:17:09 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[ASP.NET]]></category>

		<guid isPermaLink="false">http://www.billrowell.com/?p=497</guid>
		<description><![CDATA[Seeing your web site rank well in the major search engines (Google, Yahoo, MSN) is something that every web developer strives for. Making sure your web site&#8217;s pages are search engine friendly is a huge part of that effort. With ASP.NET, pages typically end in the .aspx extension. While this isn&#8217;t bad for SEO, most [...]]]></description>
			<content:encoded><![CDATA[<p>Seeing your web site rank well in the major search engines (<a href="http://www.google.com/">Google</a>, <a href="http://www.yahoo.com/">Yahoo</a>, <a href="http://www.msn.com/">MSN</a>) is something that every web developer strives for.  Making sure your web site&#8217;s pages are search engine friendly is a huge part of that effort.  With ASP.NET, pages typically end in the .aspx extension.  While this isn&#8217;t bad for SEO, most ASP.NET pages are also dynamic.  So having a dynamic page that is rendered based on a bunch of query string variables doesn&#8217;t get you anywhere with SEO, especially if you use a lot of them.  So for a while now, we&#8217;ve used <a href="http://www.isapirewrite.com/">ISAPI Rewrite</a> to rewrite your dynamic pages into something that is a lot more user friendly.  This ISAPI extension isn&#8217;t free though.  It costs $99 to purchase a license.  Not that bad, right?</p>
<p>Well recently, I discovered an Open Source solution called <a href="http://www.urlrewriting.net/149/en/home.html">UrlRewritingNet</a>.  It was originally developed in 2006 for the 2.0 framework, however the developers claim it will work all the way up to the 3.5 framework.  I&#8217;m not sure how much further development is being done though, as the last release was in August of 2006.  It is Open Source, so theoretically you can download the source and make modifications yoruself if you need to.</p>
<p>UrlRewritingNet integrates directly into your ASP.NET web application as a HttpModule.  With each incoming request, this module is called to see if the URL requested is a rewritten URL.  This isn&#8217;t too different from ISAPI Rewrite except that the rewrite for ISAPI Rewrite is handled higher up the stack by IIS itself and not the web application.  Using one solution over the other shouldn&#8217;t be much different from a performance standpoint, but tests would need run to prove it.  That&#8217;s a task for another time however.</p>
<p>The one drawback, for me anyway, was that I did see that UrlRewritingNet requires all of the rewrites to be defined in the Web.config file.  I&#8217;m not a huge fan of that.  Web.config gets cluttered up enough as it is, so the more rewrites you need the bigger this file is going to get.  With ISAPI Rewrite, all of the rewrites are stored in a separate file called httpd.ini, much like rewrites in Apache.  On the plus side, it looks like you can extend UrlRewritingNet by developing your own rewrite rule providers.  So if you need some functionality that isn&#8217;t provided, you can hook what you need up yourself.</p>
<p>UrlRewritingNet looks pretty promising and I hope I have some time to check it out and see if it is a good substitute for ISAPI Rewrite.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.billrowell.com/2009/01/20/url-rewriting-in-aspnet-isapi-rewrite-vs-urlrewritingnet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Minimizing Downtime When Deploying ASP.NET Web Applications</title>
		<link>http://www.billrowell.com/2009/01/17/minimizing-downtime-when-deploying-aspnet-web-applications/</link>
		<comments>http://www.billrowell.com/2009/01/17/minimizing-downtime-when-deploying-aspnet-web-applications/#comments</comments>
		<pubDate>Sun, 18 Jan 2009 05:21:16 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[ASP.NET]]></category>

		<guid isPermaLink="false">http://www.billrowell.com/?p=472</guid>
		<description><![CDATA[One of the annoying things I find with managing our ASP.NET web applications is that I need to &#8220;shut down&#8221; our sites when deploying a new version of our assemblies. Its not that I&#8217;m worried about visitors seeing our maintenance page for 20-30 minutes, but as search engines spider our site during this down time, [...]]]></description>
			<content:encoded><![CDATA[<p>One of the annoying things I find with managing our ASP.NET web applications is that I need to &#8220;shut down&#8221; our sites when deploying a new version of our assemblies.  Its not that I&#8217;m worried about visitors seeing our maintenance page for 20-30 minutes, but as search engines spider our site during this down time, they can&#8217;t find pages that they knew about before.  This is especially annoying when analyzing my sites in Google&#8217;s Webmaster Tools and see that I have a bunch of HTTP errors because Google couldn&#8217;t find a page because the site was unavailable.  Since Google puts a high regard on site availability and quality when determining rankings, I&#8217;d like to avoid this.</p>
<p>Deploying the site is actually very simple.  We use the XCOPY method of pushing up web forms, controls, and assemblies.  But if you just start overwriting files in the live site, users get errors or inconsistent pages.  And, if any database changes need to be made, code could not function properly before updating the site.   Any of these problems would affect my Google issue I mentioned above as well.  Not only that, but any developer worth his/her paycheck tests their changes in the live environment anyway.  So just tossing up the new version is no good.</p>
<p>I&#8217;ve been considering a few different solutions to this, but I haven&#8217;t come up with something that solves the issue completely.  At some point, I still have to take down the site.</p>
<p>One solution that I thought of was that I could set up a staging server to deploy my changes to and then run my tests there.  Once I&#8217;m satisfied with the results, I could push it to my live site, minimizing the amount of down time.  I figure the max amount of downtime using this approach would be 5-10 minutes depending on if I had to make any database changes.  Not a perfect solution, but better than the 20-30 minutes I&#8217;m experiencing now.</p>
<p>Another solution I thought of was to set up a web farm.  I could deploy the new version to one web server, make sure everything is good to go, then deploy it to the second web server.  Users could still visit the site because at least one server in the farm could handle the incoming request.  But this wouldn&#8217;t work great if database changes needed to be made.  The site itself would still have to come down.</p>
<p>So right now, solution #1 appears to be the best approach and easiest to implement.  Maybe I&#8217;m making more of a big deal of this than I need to, but I think everyone wants to minimize the downtime of their site.  The one reason I&#8217;m holding back on changing my approach is I don&#8217;t know how much Google or other search engines weigh not being able to access a site for a short period of time.  Regardless, I&#8217;m curious what other solutions developers and web teams use to deploy their ASP.NET applications to minimize site downtime.  I&#8217;m positive there is a solution to my problem, but I just haven&#8217;t thought of it yet.  If anyone has something that works for them, please chime in here!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.billrowell.com/2009/01/17/minimizing-downtime-when-deploying-aspnet-web-applications/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Speeding Up Your Web Site with YSlow for Firebug</title>
		<link>http://www.billrowell.com/2008/11/21/speeding-up-your-web-site-with-yslow-for-firebug/</link>
		<comments>http://www.billrowell.com/2008/11/21/speeding-up-your-web-site-with-yslow-for-firebug/#comments</comments>
		<pubDate>Fri, 21 Nov 2008 15:07:04 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.billrowell.com/?p=372</guid>
		<description><![CDATA[I&#8217;m always looking for an edge over our competitors to make using our e-commerce sites better from a usability standpoint. I think one of the easiest things to make the experience better is to make sure your site is responsive when people visit it, no matter what kind of connection they have or what they [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m always looking for an edge over our competitors to make using our e-commerce sites better from a usability standpoint.  I think one of the easiest things to make the experience better is to make sure your site is responsive when people visit it, no matter what kind of connection they have or what they have for a computer.  I decided to do some research on how to improve our sites download times and came across <a href="http://developer.yahoo.com/yslow/">YSlow for Firebug</a>.</p>
<p>YSlow is a Firefox extension that plugs into the <a href="https://addons.mozilla.org/en-US/firefox/addon/1843">Firebug extension</a>.  Any developer that doesn&#8217;t use Firebug is really missing out.  So if you don&#8217;t have it, get it.  Anyway, you can install YSlow right into Firefox and get access it through Firebug.</p>
<p>Upon analyzing our site the first time, we received a score of 42 from YSlow, which was an F.  Ouch.  That didn&#8217;t make me feel all that great about our site.  You can see screen shots of our initial scores <a href="http://www.billrowell.com/wp-content/uploads/2008/11/old_yslow_grade.png">here</a> and <a href="http://www.billrowell.com/wp-content/uploads/2008/11/old_yslow_stats.png">here</a>.  We scored really low for all but four of the thirteen performance criteria.  I decided to attack the easiest tasks to complete first.  This was Minify JS, Add an Expires header, and Gzip components.</p>
<p>I minified our javascript files using a utility called <a href="http://www.crockford.com/javascript/jsmin.html">JSMin</a>.  It basically removes all whitespace and line returns from your file.  It doesn&#8217;t compress the code all the way, but I wanted it to remain a little readable if I needed to look at the code on the live search.</p>
<p>Next, I wanted to handle adding an expires header.  Since we use ASP.NET and C# for our web application, I was able to write a HttpHandler to do this for me.  What was even better was I was able to handle the expires header and another issue, ETags configuration, all in the same snippet of code.  For each request, our HttpHandler adds an empty ETag and an Expires Header of 3 days in the future.  Both of these are used to determine when a cached copy of a web page needs to be refreshed.  The ETag tells the browser that the version it sees now is different from the original.  The Expires header obviously sets the expiration on the page.</p>
<p>Lastly, I wanted to GZip all of our components.  This just required configuration of our IIS Server.  You can also do this directly within your .NET application, but I didn&#8217;t see the value in this as IIS could do it for us.</p>
<p>After implementing these changes and a few other mundane ones, I ran YSlow again.  Low and behold, we&#8217;d gone from a score of 42 to a score of 76.  Not bad!  We&#8217;re now scoring a &#8220;High C&#8221; according to YSlow.  From a usability standpoint, I could definitely tell that the site responded <strong>much</strong> faster than it did when we were scoring a 42.  For those of you that would like to see screen shots of the stats, you can see them <a href="http://www.billrowell.com/wp-content/uploads/2008/11/after-yslow-performance.jpg">here</a> and <a href="http://www.billrowell.com/wp-content/uploads/2008/11/after-yslow-stats.jpg">here</a>.  Looking at the stats, you can see that we cut down the data downloaded from 413.1k to 234k, which looks like a huge improvement.</p>
<p>I strongly recommend anyone who&#8217;s developing web applications to take a look at YSlow.  You might not be able to implement changes for all of the points it says you&#8217;re not doing well for, but even 2 or 3 changes should net you some great improvements in the performance of your site.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.billrowell.com/2008/11/21/speeding-up-your-web-site-with-yslow-for-firebug/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ASP.Net HyperLink Control And Html Encoded Ampersand&#8217;s</title>
		<link>http://www.billrowell.com/2008/10/06/aspnet-hyperlink-control-and-htmlencoded-ampersands/</link>
		<comments>http://www.billrowell.com/2008/10/06/aspnet-hyperlink-control-and-htmlencoded-ampersands/#comments</comments>
		<pubDate>Mon, 06 Oct 2008 22:53:30 +0000</pubDate>
		<dc:creator>Bill</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Development]]></category>

		<guid isPermaLink="false">http://www.billrowell.com/?p=336</guid>
		<description><![CDATA[I just ran into some odd behavior with the HyperLink control ASP.Net. Per the W3C, you&#8217;re supposed to HtmlEncode ampersands, using &#38;amp; instead of &#8216;&#038;&#8217; when building URLs in your HTML code. The reason is that the &#8216;&#038;&#8217; is assumed to be an entity reference. What&#8217;s nice is most web browsers can recover from this [...]]]></description>
			<content:encoded><![CDATA[<div class="left" style="margin: 0 15px 10px 0;"><a href="http://asp.net/"><img style="margin-top: 5px;" src="http://www.billrowell.com/wp-content/uploads/2008/10/logo.png" alt="" title="ASP.NET" width="108" height="44" class="alignnone size-full wp-image-337" /></a></div>
<p>I just ran into some odd behavior with the HyperLink control ASP.Net.  Per the <a href="http://w3c.org">W3C</a>, you&#8217;re supposed to <a href="http://www.htmlhelp.com/tools/validator/problems.html#amp">HtmlEncode ampersands</a>, using <code>&amp;amp;</code> instead of &#8216;&#038;&#8217; when building URLs in your HTML code.  The reason is that the &#8216;&#038;&#8217; is assumed to be an entity reference.  What&#8217;s nice is most web browsers can recover from this type of error, but if you want your site to pass <a href="http://validator.w3.org/">validation</a>, you need to use <code>&amp;amp;</code> instead.</p>
<p>So I hooked up all of our URLs to use this method, especially when we wrote out URLs in our C# classes.  What I found odd was if I did this using a HyperLink control instead of an HtmlAnchor control, .NET would write the <code>&amp;amp;</code> out in the URL instead of using &#8216;&#038;&#8217;.  Naturally this broke our site as query string references weren&#8217;t parsed properly.  The fix was to use an HtmlAnchor instead.</p>
<p>I&#8217;m not really sure why .NET does this or if there&#8217;s another workaround for it, but this solution worked for me.  I&#8217;d be curious to know the reason behind the behavior though.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.billrowell.com/2008/10/06/aspnet-hyperlink-control-and-htmlencoded-ampersands/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

