Blog Archives

Custom URLRewriting with XML and Global.asax

utilizes my custom DocParser class here https://ronniediaz.com/2013/08/23/parse-xml-to-dynamic-expandoobject-c-net-4-0/

 void Application_BeginRequest(object sender, EventArgs e)
    {
        //string path = Request.Url.ToString();
        string path = Request.Path;

        if (Regex.IsMatch(path.ToLower(), ".*[.](jpg|png|gif|css|js|pdf|ico|woff|svg|eot|ttf)$"))
        {
            //var h = Regex.Replace(path.ToLower(), ".*/(.*)/(.*)$", "~/$1/$2", RegexOptions.Singleline);
            //Context.RewritePath(path);
            return;
        }
        
        //TODO: authorize user/request
 DocParser dp = new DocParser(Server.MapPath("~/rewrite.xml"));
        var rules = dp.GetElements("*/rule");
        
        foreach (var r in rules)
        {
            if (string.IsNullOrEmpty(r.match_url)) {
                Shared.HandleError("Global.asax::null or empty match_url encountered");
            }

            if (string.IsNullOrEmpty(r.action_url))
            {
                Shared.HandleError("Global.asax::null or empty action_url encountered");
            }
            
            if (Regex.IsMatch(path, r.match_url,RegexOptions.IgnoreCase))
            {
                List<object> qsvars = new List<object>();

                foreach (Match m in Regex.Matches(path, r.match_url, RegexOptions.IgnoreCase))
                {
                    for (int i=1;i<m.Groups.Count;i++)
                    {
                        qsvars.Add(m.Groups[i].Value);
                    }
                }
                //Context.RewritePath(string.Format(r.action_url,qsvars.ToArray()) + "&rewrite=1");
                Context.RewritePath(string.Format(r.action_url, qsvars.ToArray()));
            }
        }
}

rewrite.xml examples

<?xml version="1.0" encoding="utf-8" ?>
<rules>
  <rule match_url="^/home" action_url="~/home.aspx" />
  <rule match_url="^/login" action_url="~/default.aspx" />
  <rule match_url="^/register" action_url="~/welcome/register.aspx" />
  <rule match_url="^/logout" action_url="~/logout.aspx" />
  <rule match_url="^/default/(.*)" action_url="~/default.aspx?q={0}" />
  <rule match_url="^/test/(.*)/(.*)" action_url="~/test.aspx?q={0}&amp;r={1}" />
</rules>
Advertisement

URL Rewriting/Mapping using Global.asax

Ultimately I wound up using a different method, specified in my other blog post on URL Rewriting on GoDaddy and Shared hosting.

However, the method below is actually very useful if you are trying to do certain validation which cannot be expressed in web.config or RegEx prior to redirect, such as checking if querystring is valid and exists in database values, etc.

        //try out various request types such as absolute path and raw url to see differences
        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            string originalPath = HttpContext.Current.Request.Path.ToLower();
            //HttpContext.Current.Request.RawUrl.ToLower();
                //HttpContext.Current.Request.Path.ToLower();
            RewritePaths(originalPath);
        }

        private void RewritePaths(string originalPath)
        {
            Rewrite(originalPath, "default", "index");
            Rewrite(originalPath, "home", "index");
            Rewrite(originalPath, "index");
            Rewrite(originalPath, "login");
        }

        private void Rewrite(string path, string page)
        {
            if (path.Contains("/" + page))
            {
                if (!path.Contains(".aspx"))
                {
                    //Context.RewritePath(path.Replace("/" + page, "/" + page + ".aspx"));
                    Context.RewritePath(page + ".aspx");
                }
            }
        }

        private void Rewrite(string path, string frompage, string topage)
        {
            if (path.Contains("/" + frompage))
            {
                if (!path.Contains(".aspx")) {
                //Context.RewritePath(path.Replace("/" + frompage, "/" + topage + ".aspx"));
                Context.RewritePath(topage + ".aspx");
                }
            }
        }

URL Rewriting on GoDaddy and Shared hosting

After doing a lot of searching through google queries, forums and archives, I was finally able to solve the conundrum of using URL rewriting on GoDaddy.

The site in question is also a subdomain in a sub folder off the root site, meaning web.config rules cascade, which complicated things slightly more and was enough to send GD support over the edge.

So my site/domain/DNS setup was as follows:

//--parent
www.parentsite.com
//--and sub
subsite.parentsite.com
//--where sub is actually cname of
test.othersite.com

//--parent points to root folder
/web.config
/default.aspx
//--and sub points to subsite folder
/subsite/web.config
/subsite/default.aspx
//--desired url
/subsite/default //--should point to /subsite/default.aspx

I could not find a single article which presented a complete solution, including my own URL Mapping solution I presented in a previous article.

The simple solution in my previous article only works on GoDaddy servers if the mapping specifies a file extension on both the url and mapped url, such as:

<urlMappings enabled="true">
            <add url="~/default.aspx" mappedUrl="index.aspx"/>
            <add url="~/index.html" mappedUrl="index.aspx"/>
</urlMappings>

After speaking with GoDaddy support on 3 separate occasions, including callbacks from higher tiers, they informed me the mappings “work” and deferred to the above example..

So I dropped the simple approach of using URL Mappings, and stepped it up to URL Rewriting. According to GoDaddy kbase article, Microsoft URL Rewriting is supported, although for some reason they don’t include any examples..

I was able to at least get this working as intended after a little tweaking and reading through some of the references listed further below.

The configuration I am using is IIS7 with .Net 3.5. Haven’t tested it on 4.0 though this should work as well.

The solution:

(see code snippets above for domain structure in my scenario)

(( make sure you don't place modules or system.webServer in your web.config more than once.. you'll get a server 500 error 😛 ))

	<modules runAllManagedModulesForAllRequests="true">

<system.webServer>
    <rewrite>
      <rewriteMaps>
        <rewriteMap name="StaticRedirects">
<!-- this is similar to url mapping, but the user would actually see the aspx extension in the url -->
          <!-- <add key="/subsitefoldername/pagename" value="/pagename.aspx"/> -->
        </rewriteMap>
      </rewriteMaps>
      <rules>
        <rule name="RedirectRule" stopProcessing="true">
          <match url=".*" />
          <conditions>
            <add input="{StaticRedirects:{REQUEST_URI}}" pattern="(.+)" />
          </conditions>
          <action type="Redirect" url="http://test.othersite.com{C:1}" appendQueryString="True" redirectType="Permanent" />
        </rule>
          <rule name="default">
            <match url="default" />
            <action type="Rewrite" url="default.aspx" /> <!-- this hides the extension as intended -->
          </rule>
        <rule name="login">
          <match url="login" />
          <action type="Rewrite" url="login.aspx" />
        </rule>
      </rules>
    </rewrite>

Unfortunately however, the above example can break page validation/viewstate, but that’s a topic for another article. 😛

There is one other alternative to note that I also tried which also worked on my local server but not on GoDaddy was using Global.asax context rewrite. To avoid lengthiness, see deferred post on URL Rewriting/Mapping using Global.asax.

References
“Simple URL Rewriting/Mapping in IIS7”, https://ronniediaz.com/2011/04/06/simple-url-rewritingmapping-in-iis7/
Learn IIS, http://learn.iis.net/page.aspx/508/wildcard-script-mapping-and-iis-7-integrated-pipeline/, http://learn.iis.net/page.aspx/465/url-rewrite-module-configuration-reference/, http://learn.iis.net/page.aspx/761/provide-url-rewriting-functionality/
Stackoverflow, http://stackoverflow.com/questions/416727/url-rewriting-under-iis-at-godaddy
Rackspacecloud, http://cloudsites.rackspacecloud.com/index.php/How_do_I_rewrite_URLs_from_ASP/.NET%3F
Godaddy kbase, http://help.godaddy.com/topic/623/article/5443

Simple URL ReWriting/Mapping in IIS7

There’s an easy alternative to other over-complicated solutions on the web if your mappings are simple/static and/or you have a spare grunt to quickly and easily keep them updated without having to write a line of code.

In web.config add:

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
  </system.webServer>

Under system.web add static mappings like so:

<urlMappings enabled="true">
			<add url="~/default" mappedUrl="index.aspx"/>
			<add url="~/login" mappedUrl="login.aspx"/>
			<add url="~/logout" mappedUrl="logout.aspx"/>
</urlMappings>

Voila.

Of course some scenarios require more complex mappings, but for most non-ecomm/non-web app sites and even blogs this solution would work np, be faster to maintain without requiring assembly publishes and is less error-prone.