IHTTPModule vs IHTTPHandler

The proof of concept IHTTPModule friendly url rewriter for SUB using regular expressions.

For my previous post regarding friendly urls see here.
Edit: To read more on this topic see my next post here.

There are very important differences between IHttpHandler and IHttpModule.

Last week I was also playing around with IHTTPHandler as a way of implementing a stop-gap friendly url handler.

Now the important difference is, once the request is sent to IHTTPHandler, if it doesn’t send any content back, the user will basically see a blank page. Now that’s not to say that one handler can’t pass the request only another handler before the content is processed. But it just all seems too complex to handle that late in the request.

So, more successfully I’ve been experimenting with IHTTPModule. Basically these are loaded into a stack of modules, and all requests to your webapp pass through them. Similar to the webserver filters the modules can be fired off at various stages in the request process (within the ASP.NET dll). A few of the articles I’ve seen keep warning that if you set your module to fire too early, it can bypass the built-in security/authentication module and so forth.

So how hard is it to create a SUB IHTTPModule similar (as it can be) to things like the ISAPI rewrite utils. It seems pretty easy to match the url against a regex pattern then simply rewrite it if need be. All other requests just simply pass through the module as normal.

Example

Here is my regex pattern and regex replace string to be stored in the web.config file:
<ADD value="~/Posts/Post.aspx?postId=$3" key="/([0-9]{4})/([0-9]{1,2})/([0-9]{1,4})\-([a-z,A-Z,+]+)\.aspx$" />
Should match a url such as
http://www.kowitz.net/2006/02/35-IHTTPModule+vs+IHTTPHandler.aspx
And redirect it to:
http://www.kowitz.net/Posts/Post.aspx?postId=35

And the code required to do it? It’s just so insanely simple it hurts looking at it.

public class PostRequestModule : System.Web.IHttpModule
{
public PostRequestModule(){}

#region IHttpModule Members

public void Dispose(){}

public void Init(HttpApplication context)
{
context.AuthenticateRequest +=
new EventHandler(context_AuthenticateRequest);
}

void context_AuthenticateRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
Rewrite(app.Request.Path, app);
}

protected void Rewrite(string requestedPath,
HttpApplication app)
{
string path = app.Context.Request.ServerVariables["SCRIPT_NAME"];
NameValueCollection rules =
ConfigurationManager.GetSection("RewriterConfig/RewriterRules")
as NameValueCollection;
foreach (string rule in rules.AllKeys)
{
string sendto = rules[rule];
Regex ex = new Regex(rule, RegexOptions.IgnoreCase);
if (ex.IsMatch(path))
{
string newpath = ex.Replace(path, sendto);
string query = newpath.LastIndexOf("?") > -1 ?
newpath.Substring(newpath.LastIndexOf("?")+1) : "";
newpath = newpath.LastIndexOf("?") > -1 ?
newpath.Remove(newpath.LastIndexOf("?")) : newpath;
app.Context.RewritePath(newpath,
app.Context.Request.PathInfo, query);
break;
}
}
}
}

Ha! How about that…I just posted the entire file! Basically the idea is it loads all the regex keys from the web.config, cycles through them comparing against the current requested url, if they don’t match: do nothing. If it does match: rewrite using the replace string.

Now the great thing about rewriting at this level is, when the webform renders it resolves all the virtual paths around the current requested path, this keeps all the CSS files and images happy.

So in foresight of Darren’s up and coming changes in unifying the way all the SUB post urls are formatted, a friendly url rewriter is definitely something that should be able to be done without too much trouble.

More Info

On Regex
http://aspnet.4guysfromrolla.com/articles/022603-1.aspx
On Url Rewriting:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/urlrewriting.asp

.NET Code Snippets SingleUserBlog
Posted by: Brendan Kowitz
Last revised: 21 Sep 2013 12:15PM

Comments

Dan
Dan
10/2/2006 6:19:40 AM
Hi,
Instead of
"Regex ex = new Regex(rule, RegexOptions.IgnoreCase);
if (ex.IsMatch(path))"
inside the loop, wouldn't be better to use
Regex.IsMatch(inputString, regex, RegexOptions.IgnoreCase)?
10/10/2007 2:24:51 AM
Very nice, I have created something like that in the application layer but I think about integrating your idea into my framework.

10/10/2009 6:25:51 AM
"And the code required to do it? It’s just so insanely simple it hurts looking at it. "

You're using event handlers, casting, ternary operators, ConfigurationManager and Fod knows what else... you call it simple? Making babies is simple, having the knowledge to propertly understand your code is not.

No new comments are allowed on this post.