Why not use IHttpHandler for rewriting:
You can find the previous post I've done on this subject here, it has a c# source code example and will also explain some of the downfalls of using the IhttpHandler for rewriting. In summary my basic feeling on this is IhttpHandler is great if you know the Url that is going to be requested eg. /Rss.ashx every time an rss reader requests this Url, the reader will never know that Rss.ashx doesn't necessarily have to exist as the response is picked up and written back by the handler.
How is IHttpModule more useful url rewriting?
When it comes down to rewriting urls where the requested Url is not known or is dynamically generated IHttpModule makes it easier to manipulate the request as it passes down the asp.net stack. So creating an ASP.NET url rewriter it's just a simple matter of attaching a httpmodule that can identify the dynamic url and rewrite it before it requests a page that doesn't exist (eg a 404).
The way I chose to do this in pure asp.net was to use regex matching. Every request that comes in is tried against a regex pattern, if the url makes a match it is rewritten to the handling page (or possibly a IHttpHandler) to return the response.
But nothing beats ISAPI rewrite, right?
I'd say yes and no to this, ISAPI rewrite uses 'almost' the same principle as my module, except it rewrites the Url as it enters IIS and before the request even gets to the ASP.NET request handler. This means the client will think they are at a particular url eg /rss/ but the request could be transformed by ISAPI rewrite to /feeds/rss.ashx. One thing ISAPI rewrite can do that the .NET module can not is it is able to hide the page's language extension (eg. .aspx), but doing this is not a huge benefit unless you want to change your site's programming language which would most likely break all your referring links if the extension is present.
The ASP.NET way:
So now for the things that the ASP.NET way does better. Because the rewriting is done at the ASP.NET level, .NET knows about it, this means ASP.NET can auto-magically resolve all those virtual ~/paths correctly. There are also some other SEO advantages to doing this such as utilizing the keywords in your url as opposed to having a meaningless url full of query parameters which will get you nothing, well it might get some SEO points, but not as much as you could.
The ideal solution for ASP.NET:
I think the ideal way to do rewriting for ASP.NET is use both ISAPI in combination with a .NET module for the reasons listed above. ISAPI rewrite gives that edge of power over IIS that a class inside ASP.NET can't, so urls can look like directories ('/') rather then .aspx pages, plus the ISAPI rewrite configuration file is very convenient and configurable. The .NET module comes in handy to rewrite the url from a dynamic location to the real location of the page and is able to resolve all the ~/ virtual directories in the process.
An example of this that I've done using a combination on another site is as follows:
Request comes to: http://www.site.com/second-level/content-title/
ISAPI rewrites to: http://www.site.com/second-level/content-title/ResolvePage.aspx
My .NET module watches for requests to ResolvePage.aspx and does an ASP.NET Context.RewritePath() to the real content page location of http://www.site.com/Content.aspx?path=content-title
This then causes Content.aspx to render 'as if' it was at the requested location eg.
http://www.site.com/second-level/content-title/ResolvePage.aspx so all the virtual paths are correct in the requesting browser.
And there it is a friendly, programming language free, keyword rich url living in harmony with ISAPI and ASP.NET. Search engines are happy, users have nice clean hackable urls to look at and remember and are happy. Everybody is just happy.
Edited using Windows Live Writer, thanks Matt!