Sunday, June 19, 2011

Route to Directories That Do Not Exist On The Disc with .Net Routing 3.5

In my last post we added .Net Routing to web forms, you can find that post here: Adding .Net Routing 3.5 to Asp.Net Web Forms.

This post shows how to create a route that in the url has directories that do not exist on the disc.  Typically .Net will through a 404 file cannot be found error if a directory does not exist but .Net Routing allows you to say actually I’m going to accept that route because I know it maps to this location.

e.g. http://mydomain/site1/login/   or http://mydomain/site2/login

In that example site1 & site2 do not exist as directories on the disc, and login is the page we want to show. 
What this lets me do is have the same code running under mydomain but have different sites (which may be using different style sheets, etc).  The url will always look like it does above for each site, so users can easily bookmark it.

This lets both sites use the same pages, without deploying the same code again or creating multiple virtual directories.

How will the routes look in the Global.asax? Like this:

public static void RegisterRoutes(RouteCollection routes)
{
    // The routes:
    routes.Add("Site1Default", new CustomRoute("Site1", new URLRouteHandler("~/Login.aspx")));
    routes.Add("Site2Default", new CustomRoute("Site2", new URLRouteHandler("~/Login.aspx")));

    routes.Add(“Site1” + PageIdentifier.Login.ToString(), new CustomRoute("site1/login", new URLRouteHandler("~/Login.aspx")));

    routes.Add(“Site2” + PageIdentifier.Login.ToString(), new CustomRoute("site2/login", new URLRouteHandler ("~/Login.aspx")));

    routes.Add(“Site1” + PageIdentifier.Logout.ToString(), new CustomRoute("site1/logout", new URLRouteHandler("~/Logout.aspx")));

    routes.Add(“Site2” + PageIdentifier.Logout.ToString(), new CustomRoute("site2/logout", new URLRouteHandler("~/Logout.aspx")));
}

The first 2 routes ‘Site1Default’ & ‘Site2Default’ say if a url like http://mydomain/site1/’ is entered then by default go to the login.aspx page.

 

How can I get Normal .aspx pages to work under the missing directories?

So far by doing the above will mean that normal aspx pages will not work with the missing site1 & site2 directorues e.g. http://mydomain/site1/Login.aspx’. This will throw a 404 file not found exception. But if you want them to work you can add a couple of extra routes at the end of your existing routes like this.

routes.Add("Site1ASPX", new CustomRoute("site1/{page}", new DefaultURLRouteHandler()));

routes.Add("Site2ASPX", new CustomRoute("site2/{page}", new DefaultURLRouteHandler()));

This says everything under site1/* should be handled by the DefaultURLRouteHandler, and this route handler is expecting the {page} parameter e.g. ‘http://mydomain/site1/Login.aspx’ in this example the {page} parameter is ‘Login.aspx’.

The code for the DefaultURLRouteHandler is shown below:

/// <summary>
/// This route handler allows standard .aspx pages to work where there are directories that do not exist on disk
/// e.g. somedirectory/login.aspx will reroute to login.aspx even though on disk somedirectory does not exist
/// This can be invoked from the global.asax.cs like this:
///     var route = new CustomRoute("somedirectory/{page}", new DefaultURLRouteHandler());
/// </summary>
public class DefaultURLRouteHandler : IRouteHandler
{
    public DefaultURLRouteHandler()
    {
    }

    public System.Web.IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        string filename = requestContext.RouteData.Values["page"] as string;

        foreach (var paramUrl in requestContext.RouteData.Values)
            requestContext.HttpContext.Items[paramUrl.Key] = paramUrl.Value;

        try
        {
           var page = BuildManager.CreateInstanceFromVirtualPath("~/" + filename, typeof(Page)) as IHttpHandler;
            return page;
        }
        catch (Exception)
        {
            throw;
        }
    }
}

The line in red is where the magic happens.

Happy routing!

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.