url rewriting

A 1-post collection

Short URL Rewriting BlogEngine.NET

Since beginning this blog one of my goals was to eventually rewrite the URLs. I've recently been successful. Here's how for version 1.5. When patching borrowed software I strive for minimal changes. This is also my first foray into this subject, so as usual "it works, but it may not be right".

This particular method uses the IIS7 URL Rewrite module (v1.1). If you're hosted on an earlier version of IIS and appreciate problem solving, request to be transferred to an IIS7 server if offered, or find another method. Thanks to IIS7's web application pool isolation this is possible even with shared hosting.

Assuming your host/you have successfully installed the URL Rewrite module, the rest will be easy (though figuring it out wasn't). Here is the <rewrite> rule section to add to your site's root Web.Config:

<system.webServer>
    <rewrite>
        <rules>
            <rule name="post redirect">
                <match url="^post/(.*)\.aspx$" />
                <action type="Redirect" url="{R:1}" redirectType="Found"/>
            </rule>
            <rule name="post rewrite">
                <match url="^([0-9]{4}/[0-9]{2}/[0-9]{2})/(.*)$" />
                <action type="Rewrite" url="post.aspx?date={R:1}&amp;slug={R:2}" />
            </rule>

            <rule name="blog redirect">
                <match url="^blog/(.*)$" />
                <conditions>
                    <add input="{REQUEST_URI}" matchType="Pattern" pattern="^/blog/admin/.*$" negate="true" />
                    <add input="{REQUEST_URI}" matchType="Pattern" pattern="^/blog/User controls/.*$" negate="true" />
                </conditions>
                <action type="Redirect" url="{R:1}" redirectType="Found"/>
            </rule>
            <rule name="blog rewrite">
                <match url="^(.*)$" />
                <conditions>
                    <add input="{REQUEST_URI}" matchType="Pattern" pattern="^/blog/admin/.*$" negate="true" />
                    <add input="{REQUEST_URI}" matchType="Pattern" pattern="^/blog/User controls/.*$" negate="true" />
                </conditions>
                <action type="Rewrite" url="blog/{R:1}" />
            </rule>
        </rules>
    </rewrite>
</system.webServer>
  • The blog redirect & rewrite rules strip out the /blog web application folder from the URL. If your virtual directory is named otherwise, you will need to make that adjustment in the match, condition, and rewrite URLs. The redirect rule ensures that anyone visiting the old URL is instead taken to the new one, and the rewrite URL makes the new one actually function.

    You will note that the /admin and /User controls (extensions) folders have been excluded from this substitution, and that is because it's necessary or they will cease functioning. (Though probably fixable, I haven't yet bothered.)

  • The post rules perform a similar redirect and rewrite, stripping out the /post subdirectory, and trailing .aspx suffix allowing post links to be in the following form: http://codeoptimism.com/2009/12/04/Short-URL-Rewriting-BlogEngineNET (/blog would be in there without the other rule).

Here's where things get interesting. You may be wondering why the post rewrite rule isn't simply adding /post and .aspx in a simplistic and peaceful reflection of the post redirect rule. Ah, if only it were so easy.

BlogEngine performs its own fun rewriting in BlogEngine.Core\Web\HttpModules\UrlRewrite.cs, and the Blog-Post.aspx pages themselves are actually faked. The true URLs are in the form http://codeoptimism.com/blog/post.aspx?id=686a72df-15cb-48bb-8f56-b40ffddb6af5. So why didn't they simply drop the .aspx themselves, or why can't I modify it to do so? I believe the answer is that without the .aspx extension the server fails to direct traffic to the web app whatsoever, and that's beyond my familiarity/access.

So there still shouldn't be a problem, the .aspx would be added by the rewrite rule, right? Wrong. The rewrite is a rewrite, not a redirect, it only affects the URLs appearance and you'd be in for a nasty 404. (And before you say it, using a redirect is square one, precluding the formatting we seek.)

I simply patched BlogEngine.Web\post.aspx.cs to accept my own (.aspx included) rewritable format: post.aspx?date=2009/12/04&slug=Short-URL-Rewriting-BlogEngineNET.

You could stop there, the URLs will be correct in the address bar, though not the links on the page. For those we need to tweak the RelativeLink property of the Post class in BlogEngine.Core\Post.cs and rebuild BlogEngine.Core.dll.

If you're not one to tweak the source code you may download an otherwise vanilla 1.5 copy of BlogEngine.Core.dll from me. Throw that in the /bin folder on your site. Lastly you may wish to replace instances of <%=Utils.AbsoluteWebRoot %> in your Theme files with http://yoursite.com. I only had to change the one on the logo in site.master myself.

If you're thinking, "Hm, I should patch AbsoluteWebRoot and RelativeWebRoot in BlogEngine.Core/Utils.cs!" Knock yourself out and comment here when you've both changes working. (Unfortunately more is required, so I left them be.)

Summary

  • Copy and paste <rewrite> section above to the <system.webServer> section in your site's root Web.Config file.
  • Put my post.aspx.cs in BlogEngine folder, or patch your own.
  • Put my BlogEngine.Core.dll in BlogEngine/bin folder, or patch Post.cs & build your own.
  • Replace relevant instances of AbsoluteWebRoot in your theme files with http://yoursite.com (no /blog) if you'd like.

Discussion