Forcing Retrieval of Images in ASP.NET/MVC

Browsers cache images in order to speed up page load times. If an action on a controller generates dynamic images, this can be a problem, since the user will only see the first image fetched by the browser. One way to force the browser to by-pass its cache and actually retrieve the image is to append a random parameter to the URL for the action.
For example: A user uploads an image to the server and the server subsequently returns some HTML showing the image. The user then performs an action which triggers the server to alter the image in some way (for example cropping or resizing), and returns the HTML once again. However, the browser sees that the link to the image is the same, and therefore it simply shows the initial image which it has already cached.

So, instead of generating the image URL with razor syntax like this:

<img src="@Url.Action("GetPhoto")" />

Simply add some random parameter (or just anything the browser has not seen before) to force it to download the image again:

<img src="@Url.Action("GetPhoto", new {ticks = DateTime.UtcNow.Ticks})" />

Using the hReview-Aggregate format in PHP

Google is starting to support a number of microformats such as vCard and hReview. Google uses the term Rich Snippet for microformats.
This article shows by example how to use the hReview-aggregate format, which is ideal for sites dealing with ratings and reviews. Some well known examples of sites already incorporating the hReview format are Imdb, Rotten Tomatoes and Cnet.

As an example of how to use the hReview-aggregate format, we use a community driven site concerned with reviews of auto repair shops. On this site, each auto repair shop has a main page with its contact information and reviews written by users of the site.
On each page we wish to put a hReview markup, so that search engines and other software agents can parse the name of the shop being reviewed, its average rating and the number of user reviews.

The following PHP function writes a hreview-aggregate snippet based on a name of the auto repair shop and an array of reviews submitted by users.
It first loops through the reviews in order to obtain an average rating (one decimal place) and then the actual snippet is echoed in the RDFa format.

function create_hreview_aggregate($auto_repair_shop_name, $reviews)
{
	$average_rating = 0.0;
	$number_of_reviews = count($reviews);	
	
	if($number_of_reviews > 0) {			
		foreach ($reviews as $r)
		{	
			$average_rating += intval($r->rating);			
		}		
		$average_rating = number_format($average_rating / $number_of_reviews, 1);
	}
echo <<<EOT
<div style="display: none;" xmlns:v="http://rdf.data-vocabulary.org/#" typeof="v:Review-aggregate">
   <span property="v:itemreviewed">$auto_repair_shop_name</span>
   <span rel="v:rating">
      <span typeof="v:Rating">
      Rating:
         <span property="v:average">$average_rating</span>
         /
         <span property="v:best">5</span>
      </span>
   </span>  
   <span property="v:votes">$number_of_reviews</span> 
   <span property="v:count">$number_of_reviews</span>
</div>
EOT;	
}

This code is placed on the main page for each auto repair shop in the database. If the page comes up in a Google search result, the name of the repair shop and the average rating will perhaps sometime appear just like movies on Imdb do today

Googles presentation of Pulp Fiction on Imdb

Chances are that the snippet is just summarizing what is already visible to the human eye on the page. To avoid this redundancy, it is perfectly legal to hide the snippet.
This is what I have done in the example above by giving the div surrounding the snippet a “display: none” style.

Rich Snippets Testing Tool

At the moment, Google only supports Rich Snippets in its search results from a handfuld of major sites such as Imdb, Rotten Tomatoes and Cnet. If you are curious to see how Google interprets the semantic data on your site, you can use the Rich Snippets Testing Tool.
This is how the hReview-aggregate produced by the code above is interpreted by the tool:

How Google interprets the rich snippet from our example

This tool also helps you in ensuring that your markup is syntactically correct. There is not much point in having semantic data on your page if it isn’t parsable by a machine after all :).
Another useful, non-Google tool for this purpose is Optimus.

Lazy Linking

Imagine that you have accumulated a database of customers, businesess or some other kind of organisation (from here on: “entries”).
For each entry you have properties such as name, address and telephone number, but you are missing one essential thing: The URL for the homepage of the entry.
You could fix this the hard way and begin looking up the homepage for every single entry, but this quickly becomes time consuming (and extremely boring).

If the correctness of the link to the homepage is not mission critical, there is another, easier you could try: Google’s “I Feel Lucky” feature.

Chances are, that the names of the entries are pretty unique. This means that a Google search on the name will most likely render the homepage for the entry at the top of the search results. This also means, that had you pressed the “I Feel Lucky” button, you would have been taken directly to this homepage. The good news is that you are not restricted to using this feature by clicking the actual button on Google.com. It is also possible to use it programatically by constructing a simple query string for the Google server.

For example: The following link will take you to the homepage of the CodeIgniter framework:

http://www.google.com/search?q=CodeIgniter&btnI=3564

the btnI=3564& means that we want to use the “I Feel Lucky” feature and the string after q= is our search string, i.e. the name of our entry.

The obvious drawback of the Lazy Linking method is, that it is inherently inaccurate. There are two scenarios, where it will fail:

1: If the homepage of the entry in question is not ranked at the very top of the search results.
2: If the entry does not have a homepage at all, the user will be taken to a random page.

However, if these drawbacks can be accepted, the method is definitely a time saver.