Yesterday I was working on a C# web site project in VS 2008. After making some modifications to a class in the App_Code folder, when I later went back to the codefile for an ASPX webpage, intellisense no longer recognized the class or methods of the class I was earlier changing. I wasn't getting the normal coloring for the class name and no intellisense listing of the class's methods. Right-clicking on the class or its methods and trying to 'Go to Definition' resulted in a message stating it couldn't find the definition (or something to that effect).
I could build and run the site with no errors. I tried closing and re-opening the solution, tried closing and re-opening VS, tried deleting all the files in the Temporary ASP.NET Files directory, tried restarting IIS and tried rebooting the PC. Nothing worked. After rebooting the PC, intellisense even stopped recognizing another App_Code class. Life without intellisense sucks!
What finally did work was to right click on these classes in the solution explorer, select the 'Exclude from Project' option which excludes the files from the project by giving the files .exclude extensions, and then I right-clicked on the files again to Include them in the project. That cured intellisense.
February 8, 2009 11:03 AM
One new handy class introduced in the .NET 3.5 framework is the TimeZoneInfo class. This class allows you to get date and time information for any time zone in the world. Prior to .NET 3.5, the framework exposed methods to get date and time information only for the time zone the server was set at.
I've used this class to find the date/time of a place other than where the server is located. If you're lucky, the server your website is running on will be in the same timezone you want to save and display dates and times for. Even if you're in a different timezone, let's say in New York and your server is in California, well you can just add 3 hours to the server time to get New York time.
It isn't always this easy living in Arizona where daylight saving time (DST) is not observed. In the summer, Arizona is in the same timezone as California (PST) three hours behind the east coast and in the winter, Arizona is in MST two hours behind the east coast. Your server may be in Arizona but you want a west coast time for your application, or your server may be in California and you want Arizona time for your application.
If the server is in Arizona, and you want to know what time it is in California, you can use the TimeZoneInfo class to find this out.
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
DateTime PstDateTime = TimeZoneInfo.ConvertTime(DateTime.Now, tzi);
PstDateTime now contains the current date/time in California. This code will work year round as daylight saving time and any other adjustment rules are taken into account by the ConvertTime() static function. So, in the winter, PstDateTime will be one hour earlier than Arizona time and in the summer, PstDateTime will be the same as Arizona time. This functionality makes life very convenient since you don't need to worry about trying to calculate when DST starts and ends each year.
You may even want to just know if daylight saving time is in effect for any given date/time value.
bool IsDaylightSavingTime = tzi.IsDaylightSavingTime(PstDateTime);
This tells you whether it is daylight saving time for PstDateTime. Let's check the status of DST for two different dates:
// false
bool IsDaylightSavingTimeAprilFirst2000 = tzi.IsDaylightSavingTime(DateTime.Parse("4/1/2000"));
// true
bool IsDaylightSavingTimeAprilFirst2008 = tzi.IsDaylightSavingTime(DateTime.Parse("4/1/2008"));
There's actually a handful of other static and non-static members of the TimeZoneInfo class available that can come in handy depending on your needs. Members such as GetUtcOffset(), ConvertTimeToUtc(), DisplayName, etc. provide a wide range of built-in capability. The list of available time zones you can pass into the FindSystemTimeZoneById method can be found via the GetSystemTimeZones method.
I was working on a web page where I wanted to add a link to take the visitor to the default document of the folder this particular page is in. This page (e.g. page1.aspx) was in a folder (e.g. folder1). I actually knew the default document in this folder was index.aspx, and could have just set the link's HREF to "index.aspx", but wanted to make this a little more generic so it didn't matter what the default document was. Just to be clear, the location of the page I was putting this link on looked like:
http://www.example.com/folder1/page.aspx
Initially, I set the link's HREF to:
"../folder1/"
This worked well. It would navigate the visitor to:
http://www.example.com/folder1/
But then I needed to copy page.aspx to another folder (e.g. folder2). So the page was going to exist in both folder1 and folder2. Once I copied page.aspx to folder2, I could have manually edited the link to:
"../folder2/"
This didn't have a very generic feel to it and I would always need to remember to change the HREF if I needed to copy the page again to other folders. So I decided to make this link a server side HyperLink control and create some fairly simple .NET code that would determine what the current folder the page was in by parsing the URL and setting the link's HREF so it would take the visitor to the default document of the directory the page was in. Once the .NET code determined the folder the page was in, it ended up setting the HyperLink's NavigateUrl to something similar to:
HyperLink1.NavigateUrl = "~/folder1/";
- or even -
HyperLink1.NavigateUrl = "~/folder2/";
The worked well, but I was surprised when I looked at the HTML source to see what the HREF resolved to. It essentially looked like:
<a id="HyperLink1" href="./">Go to the root of this folder</a>
As you can see, a HREF of "./" is the default document or root of the current folder! Instead of running this .NET code I created to parse the URL and determine the current folder name, all that's needed is just statically setting the HREF to "./". This gave me flashbacks to the old DOS days where running a simple DIR command (in a directory other than root) always results in the first two lines being:
<DIR> .
<DIR> ..
The "." DIR refers to the current folder and the ".." DIR refers to the parent folder. You can still see this today by opening up a command prompt and running DIR.
It's also worth mentioning that you can use "./" when redirecting a visitor in server side code:
Response.Redirect("./");
I'm sure I'll now start finding lots of places to sprinkle "./" HREFs in!
Do you add enough comments to your code? Too many, perhaps? The last few months, I've realized how helpful comments in source code can be. Years ago, I wasn't a big comment guy. I think I didn't want to spend the time commenting and felt like if I (or someone else) looked at the code for a couple of minutes, they would understand what's going on. This is basically true, but comments remove or reduce the need to spend those few minutes studying the code to see what's going on. When maintaining code, you still need to understand the code before making any changes, but spending 30 seconds, a minute or even a few minutes to add comments when you're writing code and everything is fresh in your mind is really proving to be beneficial when going back over code in the future.
There's also times when there are no comments and after spending a few minutes reacquainting myself with some code, I'm still not 100% sure if I fully grasp why something was done a certain way. Comments are priceless for these cases too.
The other thing I've started doing as well is including a date with my comments (including the year!). It all may seem unnecessary and a waste of time when writing code, but more times than not, pays off in the future.
Turning off viewstate for an entire page or just for certain controls can potentially reduce bandwidth greatly. This is not news for most developers, but at least for me, I often forget to take this into account when developing ASP.NET pages.
Just the other day, I found two server side controls that had enough content in them to make viewstate much larger than it should have been. After disabling viewstate on those 2 controls, the viewstate hidden field sent to the client went down from about 6,500 bytes to 500 bytes! That's 6 KB of unneeded data that was being sent down to each client. And because viewstate is sent to the client in a hidden input field, if there's a postback, all that data gets sent back up to the server. Most people don't have a very fast upload speed, so the post hurts performance more than sending the data to the client.
Especially for pages that don't do any postbacks, there's no reason I can think of to even have viewstate turned on at all. For these pages, disable viewstate at the page level. It's scary to imagine the number of ASP.NET pages out there that output static reports in large tables (gridview, datagrid, listview etc) with viewstate unnecessarily enabled. Bandwidth savings on such pages could probably be as large as the tens or even hundreds of kilobytes.
There are reasons to leave viewstate enabled for server controls on pages that do postbacks, however. During a postback, if the resources required are high for obtaining the data needed to put back into a disabled viewstate control, it may be more advantageous to leave viewstate enabled. For instance, if you need to make a database call or consume a web service across a network to obtain the data, leaving viewstate turned on may be better. Same with most standard form controls (e.g. input, select), there's typically not going to be enough of a performance gain to justify turning off viewstate and losing some of the perks you get with viewstate enabled when a page is going back and forth between the client and server one or more times. The big performance gains are going to be with server controls that output large blocks of HTML not editable by the user.
October 19, 2008 11:17 AM
It's an unfortunate reality that after updating an external CSS or JavaScript file referenced from a web page, not all browsers that have been to your site before will detect an updated file it has previously cached. When this happens, browsers are running outdated JS and applying old styles to your page elements.
One of the common workarounds for this situation that I've found quite effective is to append some value to the query string of the external file. So instead of the typical link (to a CSS file) in the Head section of your document,
<link href="styles.css" type="text/css" rel="stylesheet" />
You instead use a link with an arbitrary value following the actual file name:
<link href="styles.css?v=1" type="text/css" rel="stylesheet" />
Browsers cache the CSS file with an Id of "styles.css?v=1". If you update your CSS file, you can change the "v=1" to "v=2" in your HTML page and the browser treats styles.css?v=2 as a different file than styles.css?v=1. Since styles.css?v=2 isn't already cached, the browser will fetch the latest copy of styles.css from your web server. Constantly modifying (and trying to remember to modify) the query string value when I make changes to CSS and JS files has always been a manual task for me. Recently, however, I created a mechanism to automate this process.
The automated process appends the timestamp of the external file (CSS of JS) to the query string following the file's name that is sent to the browser. The file timestamp is stored in the .NET cache with a cache dependency to the actual file on the web server. Whenever I update the CSS or JS file, the timestamp is automatically removed from the cache and the next time a visitor arrives at the page and the timestamp is needed, the timestamp is retrieved and stored in cache. The purpose of the cache is to obviously reduce the amount of file I/O and overall time required in getting the page to the browser. I've fallen in love with this process as it's made my life easier!
The download link at the bottom of this post contains the code for a static GetFileWithVersion() function. The same function can be used for any external file that you want to prevent browsers from mistakenly hanging onto a copy of after you may have updated the file. At present, GetFileWithVersion returns a string value containing the filename and appended query string value. It's the caller's responsibility to add the necessary link or script tag to the head section of the page.
Example usage of the GetFileWithVersion() function with a CSS file:
string CssFileWithVersion = utils.GetFileWithVersion("MainCss", "~/styles.css");
System.Web.UI.HtmlControls.HtmlLink cssLink = new System.Web.UI.HtmlControls.HtmlLink();
cssLink.Href = CssFileWithVersion;
cssLink.Attributes.Add("type", "text/css");
cssLink.Attributes.Add("rel", "stylesheet");
this.Header.Controls.Add(cssLink);
Example usage of the GetFileWithVersion() function with a JavaScript file:
string JsKey = "MainJs";
if (!ClientScript.IsClientScriptIncludeRegistered(this.GetType(), JsKey))
{
string JsFileWithVersion = utils.GetFileWithVersion(JsKey, "~/tools.js");
ClientScript.RegisterClientScriptInclude(this.GetType(), JsKey, ResolveClientUrl(JsFileWithVersion));
}
I've been using the GetFileWithVersion() function from master pages and standalone pages for a few weeks now. Putting this type of mechanism in place is definitely a time saver and since implementing this, I personally haven't seen or heard of any issues with old CSS or JavaScript showing up.
Code Download (1.74 kb)
September 26, 2008 8:12 PM
It's important to realize a JavaScript event is not guaranteed to fire. The events I have in mind are events such as onmouseout and onmouseover. I'm sure there are many other events that also may not fire depending on the circumstances at the time the events would normally fire. If the element is right up against the edge of the browser viewport when the mouse moves away from the element and out of the browser, or if the browser or computer is busy processing something else at the time the event would be expected to occur, it may just not happen.
While working with jQuery recently I created a rollover image with the hover() function to show a different image when the mouse rolls over the image. The particular piece of code was:
oImgBtn.hover(
function(){ this.src = this.src.replace('.gif','_over.gif'); },
function(){ this.src = this.src.replace('_over',''); }
);
This code works good assuming your rollover image has the same filename as the original image with "_over" at the end of the filename. The problem occurred one time while testing the page. I noticed the image replacement was not occurring and I was getting some ugly flickering when hovering over the image. Fortunately, I had Firebug already turned on and checking the Net tab showed a red item indicating a 404 error. The file that the browser was getting a 404 on had this filename:
myImage_over_over.gif
Apparently, one of the previous times I had rolled over the image, for whatever reason the onmouseout event didn't fire leaving the images source as myImage_over.gif (the rollover image). The next time I rolled over the image, the onmouseover event fired changing the image's source from myImage_over.gif to myImage_over_over.gif. Not good! A very easy and effective solution in this case was to make sure a preexisting "_over" in the image source was removed prior to adding it back in the onmouseover event handler.
oImgBtn.hover(
function(){ this.src = this.src.replace('_over', '').replace('.gif','_over.gif'); },
function(){ this.src = this.src.replace('_over',''); }
);
This is a much more robust method of making sure things don't fall apart in the rare event a JavaScript event doesn't fire. Although rollover images are not usually critical to a page's functionality, it's still a bad experience to the end user if they see things flickering that shouldn't be flickering. This also makes you realize that for any client side code, it's important to not assume events will always fire and be sure your code is defensively designed so it can recover from unexpected situations.
September 21, 2008 3:45 PM
This is the first blog post on Ben's Quarters. If you search for a post prior to this one, you simply won't find one!
I'm excited to finally put a blog on the web. I can't tell you how many times I've had some code sample, problem, idea, rant or thought to share, but didn't have anywhere to post! Well, those days are now over. Although I don't anticipate very frequent posting, I do hope to post on a consistent basis.
If you don't know me, don't fret -- I put together an "About Me" page (see link on left side).
The focus of posts on Ben's Quarters will be programming and software development related. This is a large field. My software development career has revolved around Microsoft technologies -- .NET, Visual Studio, SQL Server, etc.
I finally got a chance to work with jQuery a couple of weeks back. I'm honestly not crazy about these types of libraries and have actually never used a JS library prior to jQuery. There was definitely a learning curve and I wouldn't say that I can't live without it. It seems like most JavaScript I need is not a big deal to just create straight without any libraries. I see the biggest benefit of using a library such as jQuery is the cross browser support it gives you. But again, the JavaScript I usually create without jQuery for validating input and manipulating some elements on the page already seems to run fine in the browers I test against. I still don't mind incorporating jQuery into some web projects I work on, but don't feel like I need to.
I actually have a short jQuery related post I'll get up shortly. It'll be post #2
September 20, 2008 9:28 PM