Yearly Archives: 2009

Get jQuery intellisense in VS.Net when using a CDN

I recently heard about this technique to get jQuery intellisense working in Visual Studio .Net.  jQuery intellisense traditionally has never worked properly for me because I don’t use <head runat="server"> and thus don’t link to javascript files the MS way.  Most of the sites I build today just reference jQuery on a CDN like Google or Microsoft and that breaks Visual Studio’s ability to find the associated vsdoc.js file.  This works, however:

Add the following line to your master page file in the <head> element area under your normal jQuery script tag.

<% /* %><script type="text/javascript" src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2-vsdoc.js"></script><% */ %>

That line wraps the script tag in comments, so the script tag never gets rendered on the client side.  Visual Studio sees a valid file, though, and provides intellisense based off the comments in that file.  Below is a full example page layout:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Example jQuery Intellisense</title>
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
  <% /* %><script type="text/javascript" src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2-vsdoc.js"></script><% */ %>

  <!– Add your own javascript here –>

</head>
<body>
   Do work son
</body>
</html>

Balsamiq

I heard about Balsamiq recently and figured I’d pass it along.  It’s a nice tool for quickly creating screen mockups.  After playing with it for about 5-10 minutes this morning, I’ve got to say that I’m impressed.  I definitely think it is a nice alternative to using powerpoint.  It is an Adobe AIR application which means that it’ll run on mac, windows, or linux.  They even allow you to test it out online, at their website.  Check it out!

Disclaimer: This is a bit of an ad, to get a free license, but look through this blog and show me where else I blog about other people’s products.  It’s not very often, so believe me when I say that this one is worth it!

IIS7: How to quickly and easily optimize your website using GZip compression

DmbStream is starting to gain some momentum and I want the site to be received as fast as possible. It has over 1,100 registered users now, so every little optimization helps.  I used YSlow to pinpoint some of the major issues with the site and it really shed some light on the bottlenecks.

The first thing I did was use Google to host jQuery. This is an obvious win… The more sites that use Google to host their ajax libraries, the greater the possibility that the user will already have that library in their browser cache. Plus it offloads about 60k of javascript to Google’s CDN for each virgin request.

After that, YSlow said that javascript files were not getting gzip compressed. I have DmbStream hosted with IIS7, so things *should* be easy to configure. After reading this article, I added the following to the <system.webServer> element in my web.config file:

<staticcontent>
    <remove fileextension=".js" />
    <mimemap mimetype="text/javascript" fileextension=".js" />
</staticcontent>

Finally, the html output needed some compression. Once again, IIS7 makes this pretty simple to configure once you find the magic elements to add to the web.config. This article gives a good overview of the elements to add to web.config while this article describes using iis7 dynamic compression with output caching.

For my needs, I just added the following to the web.config <system.webServer> element:

<urlcompression dodynamiccompression="true"></urlcompression>

So what are the results?

Original:
Empty browser cache: 123.2K
Primed browser cache: 48.5K

Enabling gzip and dynamic content caching:
Empty browser cache: 80.3K
Primed browser cache: 9.5K

That’s a reduction in size of 35-80% per request. Port80 says that these improvements speed the site up 6.1 times. Not too bad, for just adding a few lines to the a web.config.

I have some other tweaks that I’ll continue playing with (it looks like .gif files aren’t being compressed), but by far the most useful compression came from turning dynamic compression on. In other terms, compressing the generated HTML output.

If you’re looking for some more reading material regarding IIS7 compression, I recommend checking out this post as well.

Helper to access route parameters

I had a need to access routing information that was not readily accessible (as far as I could discover).  So, I wrote this helper to allow me to get the string, object pairs that Routing parses from the URL:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Routing;

namespace BiaCreations.Helpers
{
    public class RouteHelper
    {
        private static IDictionary<string, object> _values;
        public static IDictionary<string, object> GetRouteInfo(HttpContext context)
        {
            if (_values == null)
            {
                HttpContextBase contextBase = new HttpContextWrapper(context);
                RouteData data = RouteTable.Routes.GetRouteData(contextBase);

                RequestContext requestContext = new RequestContext(contextBase, data);

                _values = requestContext.RouteData.Values;
            }
            return _values;
        }

        public static T GetRouteInfo<T>(HttpContext context, string key)
        {
            IDictionary<string, object> data = GetRouteInfo(context);

            if (data[key] == null)
                return default(T);

            object objValue = data[key];
            // It appears that route values are all strings, so convert the object to a string.
            if (typeof(T) == typeof(int))
            {
                objValue = int.Parse(data[key].ToString());
            }
            else if (typeof(T) == typeof(long))
            {
                objValue = long.Parse(data[key].ToString());
            }
            else if (typeof(T) == typeof(Guid))
            {
                objValue = new Guid(data[key].ToString());
            }
            return (T)objValue;
        }
    }
}

There are probably better ways to do this, but I needed this functionality and this works.  I am open to suggestions, though, if you have a better way of accomplishing this.  Oh, and my use case for needing this was that I needed value of the "id" parameter passed to a view, within an asp:substitution callback function.  I know that doesn’t completely follow the MVC philosophy, but you have to work with what you’re given, and sometimes it’s worth bending rules for the benefits that output caching can provide.

Migrate email from Gmail to Google Apps

I, among others, have searched for a solution to transfer email in my gmail account to my google apps email.  There isn’t a formal way of doing so via Google, but low and behold I stumbled across a way to do it with Linux!  Consider this an addendum to that post, with complete instructions for those not familiar with linux.  I wanted to keep all of the labels, stars, read status, and email date.  As an added bonus, this method allows you to change the recipient value on emails so that it shows that it came from “me” rather than your gmail address.  I used Amazon EC2 to work the magic for me and 46k emails later, I’m a happy google apps user 🙂    You can just as easily use your own linux box alternatively.

This is how you can transfer your email from Gmail to your Google Apps email:

  1. Log into Amazon EC2 and select a Fedora instance.  It doesn’t really matter which instance you use.  I used “Basic Fedora Core 8 (AMI ID: ami-5647a33f)”
  2. Follow the example video on Amazon’s website for how to SSH into your instance
  3. Log in as root
  4. Install imapsync by running “yum install imapsync”
  5. Edit a script by running “nano run-imapsync”
  6. Paste in the following:
    imapsync –host1 imap.gmail.com
    –port1 993 –user1 user@gmail.com
    –passfile1 ./passfile1 –ssl1
    –host2 imap.gmail.com
    –port2 993 –user2 user@domain.com
    –passfile2 ./passfile2 –ssl2
    –syncinternaldates –split1 100 –split2 100
    –authmech1 LOGIN –authmech2 LOGIN
    –justfolders

    imapsync –host1 imap.gmail.com
    –port1 993 –user1 user@gmail.com
    –passfile1 ./passfile1 –ssl1
    –host2 imap.gmail.com
    –port2 993 –user2 user@domain.com
    –passfile2 ./passfile2 –ssl2
    –syncinternaldates –split1 100 –split2 100
    –authmech1 LOGIN –authmech2 LOGIN
    –regexmess ‘s/Delivered-To: user@gmail.com/Delivered-To: user@domain.com/g’
    –regexmess ‘s/<user@gmail.com>/<user@domain.com>/g’
    –regexmess ‘s/Subject:(s*)n/Subject: (no–subject)$1n/g’
    –regexmess ‘s/Subject: ([Rr][Ee]):(s*)n/Subject: $1: (no–subject)$2n/g’

    Replace name@gmail.com with your Gmail address and name@domain.com with your Google Apps email address

  7. Press Control-x to save the file and quit nano
  8. Make the script executable by running “chmod 744 run-imapsync”
  9. Create a file containing your Gmail password by running “nano passfile1”
  10. Type in your Gmail password and press Control-x to save the file
  11. Create a file containing your Google Apps password by running “nano passfile2”
  12. Type in your Google Apps password and press Control-x to save the file
  13. Execute the script by typing “./run-imapsync”

Depending on the size of your mailbox, you’ll have nirvana in a few hours 🙂  Transfering my 46k emails weighing in around 2.5Gb took roughly about a day… I had to babysit the process because it failed after a while for some unknown reason.  But restarting it with the specified –maxage param will get you right back near where you left off.  You may notice that I call imapsync twice in my script file.  It was failing on messages that had multiple labels and the folders weren’t created yet.  So the first call creates all of the folders while the second call moves all of the messages.