... or any other ASP.NET based system

At the company i work at, we used to sell our own custom made CMS-like system. This was a great success, and the product had many customers. Since we have moved towards using Sitecore, our own CMS has been slowly phased out. It is still around, but we advise customers to upgrade to Sitecore, as it is a way better platform for a website these days.
One of our largest customers on the old system has finally transferred to Sitecore, and we are currently in the process of implementing their site. The new page in Sitecore will get a brand new fancy responsive web design, but the content, mostly products will remain the same. The challenge is that urls to products will change when add them to Sitecore.
In the old system, we were using classic ASP, and differentiating between products, by adding ID’s to the query string like:

http://domain.dk/shop.asp?t=5&id=553

In the above, t is the type, which indicated a product group, and ID is the id of the product group.

Another example is

http://domain.dk/shop.asp?t=1&id=35000

This indicated that it was a product, with ID 35000.
When moving to Sitecore the urls looks like this instead

http://domain.dk/products/ebooks/cargo/ebook-ibc-code-2007-edition

Indicating that the product group is “cargo”, and the product name is “ebook ibc code 207 edition”.
The new urls are perfect for human reading, but is also SEO optimized. Our problem is that all search engines knows the old format, and has indexed around 7.000 product pages in that format. If we do nothing, all links to the old pages, will return a 404, and the SEO that is built up, will be wasted. Instead, we want to make a handler that maps the old product ID’s to the new urls in Sitecore. This is done quite simple, as we  can get a list of the old ID’s mapped with the products Item numbers, and in Sitecore, we have a method for getting the Sitecore item based on the item number.
The handler
Adding the handler to web.config is easy, we want to catch all requests to shop.asp, and handle them. This is done be adding the following line to web.config in the handlers section of system.webServer

<add verb="GET,HEAD" path="shop.asp" type="OxygenSoftware.Kernell.SEOCompatability.ASPHandler, OxygenSoftware.Kernell" name=" OxygenSoftware.Kernell.SEOCompatability.ASPHandler " />

The class ASPHandler is implemented like the following:

public class ASPHandler : IHttpHandler
{
   public void ProcessRequest(HttpContext context)
   {
      Sitecore.Context.SetActiveSite("website");
      var t = WebUtil.GetQueryString("t", "");
      var id = WebUtil.GetQueryString("id", "");
      if (t == "1")
      {
         var url = String.Empty;
         var itemNo = MappingHelper.GetProductItemNoFromProductID(realID);
         var newItemWithItemNo = MappingHelper.GetItemFromItemNo(itemNo);
         if (newItemWithItemNo != null)
            {
               url = LinkManager.GetItemUrl(newItemWithItemNo)
            }
            else
            {
               url = String.Format("/search?search={0}", itemID);
            }
            context.Response.RedirectPermanent(url, true);
         }
         if (t == "5")
         { 
// Almost same logic as above
         }
         Log.Info(String.Format("ASPHandler, couldnt process request: {0}, redirecting to frontpage", context.Request.RawUrl), typeof (string));
         context.Response.RedirectPermanent("/");
      }
   }
}

The key things to notice in the class is that we are using Response.RedirectPermanent. This method will return a 301, permanently redirected to the search engine when it crawls an old url, and tell it to visit and index the new product page instead. For fallback, we have implemented that the system will do a search for the item, if not found.
As a note, we have implemented the handler to listen to all .asp files, in that way, we incept all requests to an asp file, no matter what the name is, if we don’t know what to do with the request, we simply send the user to the frontpage.