Typically Url resolving is done by going from relative to absolute, but there are a few cases where you need to go in the opposite direction.  One of those that I commonly see is when an application is using the Server.Transfer method, which only accepts relative Url’s.

To handle converting absolute url’s to relative ones, I’ve been using an extension method similar to the following:

public static string ResolveAbsoluteUrlToRelativeUrl(this Control control, string absoluteUrl)
{
    string relativeUrl = string.Empty;

    /* Build protocol + server name + port + application path */
    string protocol = control.Page.Request.ServerVariables["SERVER_PORT_SECURE"];
    if (protocol == null || protocol == "0")
        protocol = "http://";
    else
        protocol = "https://";

    /* If the port is null, default http or https, we don't need to add it */
    string port = control.Page.Request.ServerVariables["SERVER_PORT"];
    if (port == null || port == "80" || port == "443")
        port = "";
    else
        port = ":" + port;

    string server = control.Page.Request.ServerVariables["SERVER_NAME"];
    string applicationPath = control.Page.Request.ApplicationPath;

    string serverPath = protocol + server + port + applicationPath;

    /* If we don't find the serverPath at the beginning of the Url, 
     * we'll just return the passed in absolute */
    if (absoluteUrl.ToLower().StartsWith(serverPath.ToLower()))
        relativeUrl = "~" + absoluteUrl.Remove(0, serverPath.Length);
    else
        relativeUrl = absoluteUrl;

    return relativeUrl;
}

The code is relatively* straight-forward, and gracefully returns the absolute Url if the relative one cannot be formed.  Since the code requires access to the current request object, making the entire method an extension keeps the code a bit more elegant and enforces that it can only be called in the correct environment.

- Colin

* pun intended!