Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement URL rewriting with Windows Azure?

I have an ASP.NET / C# website that's hosted on Windows Azure. The site is a predictions-based social site with a feed of prediction summaries on the main page. If you click on a summary, you're redirected to the details page for that prediction using a simple QueryString.

For example:

http://www.ipredikt.com/details.aspx?id=14

This particular prediction is entitled "Paris Hilton will win the Nobel Peace Prize" so what I'd like to do is implement URL rewriting for my site on Azure as follows:

http://www.ipredikt.com/predictions/14/paris-hilton-will-win-the-nobel-peace-prize

What are some strategies and best practices for doing this? And can someone point me to a good Azure-specific article or two.

The hyphenated title ("paris-hilton-bla-bla") is really just to make the URL more human readable; I don't envision relying on it at all in terms of loading pages. In fact, I'd probably allow duplicate titles since I'll be relying on the prediction ID in the URL.

EDIT:

Forgot to mention that we are NOT based on MVC. We came up w/ our own architecture that uses PageMethods and WebMethods to return JSON to the client. We rely on ASP.NET AJAX to do all of the JSON serialization, and almost all of our UI is built dynamically on the client using jQuery.

EDIT: SOLUTION

Thought I'd share my solution now that I have things up and running.

I made a new class as follows (copied verbatim from somewhere):

public class WebFormRouteHandler<T> : IRouteHandler where T : IHttpHandler, new()
{
   public string VirtualPath { get; set; }

   public WebFormRouteHandler(string virtualPath)
   {
      this.VirtualPath = virtualPath;
   }

   public IHttpHandler GetHttpHandler(RequestContext requestContext)
   {
      return (VirtualPath != null)
          ? (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath(VirtualPath, typeof(T))
          : new T();
   }
}

I added the following method to Global.asax. The actual method is MUCH, much longer (it covers every page in the site). You'll see that I support calling the predictions page in lots of different ways: with an id, with an id + title, etc. (The "...fb" versions of pages are for the Facebook app version of my site which use a different MasterPage.)

  public static void RegisterRoutes(RouteCollection routes)
  {
     // Details : 'predictions' Page
     var routeHandlerDetails = new WebFormRouteHandler<Page>("~/details.aspx");
     var routeHandlerDetailsFb = new WebFormRouteHandler<Page>("~/detailsfb.aspx");

     routes.Add(new Route("predictions/{id}", routeHandlerDetails));
     routes.Add(new Route("predictions/{id}/{title}", routeHandlerDetails));

     routes.Add(new Route("fb/predictions/{id}", routeHandlerDetailsFb));
     routes.Add(new Route("fb/predictions/{id}/{title}", routeHandlerDetailsFb));
   }

...and this method is called from Application_Start()

  void Application_Start(object sender, EventArgs e)
  {
     RegisterRoutes(RouteTable.Routes);
  }

Then I added the following to web.config in the system.webServer block:

   <!-- Added for URL Routing -->
   <modules runAllManagedModulesForAllRequests="true">
      <add name="UrlRoutingModule"
           type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
   </modules>

    <!-- Added for URL Routing -->
    <handlers>
      <add name="UrlRoutingHandler"
           preCondition="integratedMode"
           verb="*"
           path="UrlRouting.axd"
           type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
   </handlers>

I also had to exclude the virtual "predictions" directory from authentication (because almost all parts of our site are accessible my non-auth users):

<!-- Url routing -->
<location path="predictions">
   <system.web>
      <authorization>
         <allow users="*" />
      </authorization>
   </system.web>
</location>

Finally, I no longer rely on QueryString string parameters when loading pages, so I had to write some new helper methods. Here's one that extracts a numerical value from the new routing URL (I'll be cleaning this up to only have a single 'return'.):

  public static int GetRouteDataValueAsNumber(HttpRequest request, string propertyName)
  {
     if ((request == null) ||
         (request.RequestContext == null) ||
         (request.RequestContext.RouteData == null) ||
         (request.RequestContext.RouteData.Values[propertyName] == null))
     {
        return -1;
     }

     try
     {
        return System.Convert.ToInt32(request.RequestContext.RouteData.Values[propertyName]);
     }
     catch
     {
     }

     return -1;
  }

Now when I need to read a routing value (like a prediction ID), I do the following:

  long _predictionId = System.Convert.ToInt64(WebAppUtils.GetRouteDataValueAsNumber(Request, "id"));

Works great! Now my site feels like an MVC app with friendly and self-documenting URLs.

Oh, last thing, you also need to enable HTTP Redirection as follows:

Start => Control Panel => Program => Turns Windows Features On => Internet Information Services => World Wide Web Services => Common HTTP Features => (select checkbox for) HTTP Redirection.

like image 286
Armchair Bronco Avatar asked Jun 18 '11 18:06

Armchair Bronco


People also ask

What is the difference between URL rewriting and redirecting?

Simply put, a redirect is a client-side request to have the web browser go to another URL. This means that the URL that you see in the browser will update to the new URL. A rewrite is a server-side rewrite of the URL before it's fully processed by IIS.


2 Answers

The easiest way to implement this would be a programmatic approach using the System.Web.Routing assembly.

This basically works by including the UrlRoutingModule in your web.config, and defining patterns that resolve the target page based on matching routes. If you are familiar with ASP.NET MVC, then you have used this routing strategy before, but MVC is not necessary to use Routing.

Here are some resources to help you get started:

  • MSDN Documentation for the System.Web.Routing namespace - official documentation

  • Scott Gu on URL Routing for MVC - * Note that this article explains routing in the context of an ASP.NET MVC application, however, the same methodology will work regardless of whether or not you are using MVC

  • ASP.NET Routing... Goodbye URL rewriting, by Chris Cavanagh - An explanatory article

  • Exploring System.Web.Routing, by Justin Etheredge - A case study explaining how to use routing independently of the MVC architecture

About Windows Azure ...

If you take this approach, it doesn't really matter that you are using Windows Azure. However, I found an article by Michael Kennedy called ASP.NET Routing in Windows Azure Using WebForms, explaining how to easily deploy such a solution on Windows Azure. The article even has a sample project for download.

like image 154
smartcaveman Avatar answered Oct 23 '22 17:10

smartcaveman


Azure web roles have the IIS7 Url Rewriting module installed - http://msdn.microsoft.com/en-us/library/dd573358.aspx

The "how to" for this module is at http://learn.iis.net/page.aspx/460/using-the-url-rewrite-module/

For your Paris example, you basically need to setup a rule that maps the url

http://www.ipredikt.com/predictions/14/paris-hilton-will-win-the-nobel-peace-prize

to

http://www.ipredikt.com/details.aspx?id=14

This is something like:

Pattern -

^predictions/([0-9]+)/([_0-9a-z-]+)

Action -

 details.aspx?id={R:1}

For more on defining these rules see http://learn.iis.net/page.aspx/461/creating-rewrite-rules-for-the-url-rewrite-module/

like image 40
Stuart Avatar answered Oct 23 '22 15:10

Stuart