Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IIS 7.5 URL rewrite module and URL routing in Global.asax for sub-applications

I have a "top-level" web-site, www.ccesd.ac.uk, and various "lower-level" web-sites running off it such as www.ccesd.ac.uk/BritSocAt that are separate sites but share a lot of code. These lower-level sites are specified as web applications in IIS 7.5 and inherit a common web.config file from www.ccesd.ac.uk, although they live in their own application pools.

I have configured IIS 7.5 with the URL Rewrite module so that the lower-level sites can have their own distinct URLs, e.g. www.BritSocAt.com, which maps to www.ccesd.ac.uk/BritSocAt.

Web-site configuration in IIS 7.5

Each site has its own Global.asax file with URL routing rules defined for pretty URLs. These URLs (/Home, /About, /Contact etc.) are common to all sites, including the top-level (ccesd.ac.uk) site.

    void Application_Start(object sender, EventArgs e)
    {
      // Code that runs on application startup
      RegisterRoutes(System.Web.Routing.RouteTable.Routes);
    }

    // ** URL ROUTING **
    private static void RegisterRoutes(System.Web.Routing.RouteCollection routes)
    {
      routes.Ignore("{resource}.axd/{*pathInfo}");
      // HOME
      routes.MapPageRoute("Home", "Home", "~/Body.aspx", false, new System.Web.Routing.RouteValueDictionary
 { { "control", "HomePage" } });
      // CONTACT US
      routes.MapPageRoute("ContactUs", "Contact", "~/Body.aspx", false, new System.Web.Routing.RouteValueDictionary
 { { "control", "CCESDContactUs" } });
      // ABOUT US
      routes.MapPageRoute("AboutUs", "About", "~/Body.aspx", false, new System.Web.Routing.RouteValueDictionary
 { { "control", "CCESDMissionStatement" } });
    }

I understand from Ruslan Yakushev's excellent tutorial that the IIS URL rewriting module is processed before the ASP.NET routing in Global.asax. This is the way I need it to work. However, if I type www.britsocat.com/About, I find that the Global.asax file for www.ccesd.ac.uk is being used! (I have verified this in testing.) Furthermore, this takes place before IIS URL rewriting. In other words, the resulting page served is www.ccesd.ac.uk/Body.aspx?control=CCESDMissionStatement instead of www.ccesd.ac.uk/ BritSocAt /Body.aspx?control=CCESDMissionStatement.

I suspect this is because I have the same routing rule ("About") in both sites (Global.asax files). I think I could fix this by changing the name of the rule in one of the files; but that's undesirable in general, especially for "Home".

Is there anything I've missed or anything I can do to fix it?

like image 642
Ed Graham Avatar asked May 14 '13 22:05

Ed Graham


1 Answers

After a lengthy conference with the MSDN Support Team, it appears that this cannot be done: the official response was that IIS ARR and URL Rewrite were not designed to be used to map separate domain names to sub-applications in the manner described above. This ties in with the fact that one can't bind a separate domain name to a sub-application in IIS, only to a root-level web-site. The officially recommended approach is to have separate web-sites in IIS for each distinct domain name (i.e. one for britsocat.com, one for ccesd.ac.uk etc.).

For those who are interested, what was happening was that ARR was not aware of the fact that /BritSocAt was a sub-application of ccesd.ac.uk; once the redirection (or rather, rewriting) had taken place, /BritSocAt was treated as a standard virtual directory instead. Thus once a matching rule for a friendly URL had been found in the root-level Global.asax file, no further searching took place and the more specific /BritSocAt Global.asax file was ignored. (Contrast this to the situation without ARR, where the sub-level Global.asax file was used in preference.) I tried to dodge this by moving my routing rules from the various Global.asax files to the Init() methods of corresponding HttpModules instead, and then having the root-level web.config file specify the root-level module and then the /BritSocAt web.config file specify its own module (having first removed the root-level module). The result was exactly the same, however; with ARR in use, the sub-level web.config was simply being ignored. (I tested this by putting a non-existent module name in it -- no error!) I even tried hacking the root-level module so that it ignored all requests to /BritSocAt address; however since IIS7, using "integrated mode" has the consequence that the request information is no longer available for use in the Init() method of a module (by design). Finally, I tried moving all my routing rules into IIS (from Global.asax); this got me closer but my site was still doing some very odd (and unexplained) things, and it was 7pm on a Friday before a Bank Holiday weekend by this point, so I gave up.

My residual feeling is one of mild disappointment: I think this limitation of IIS ARR/URL Rewriting should be made clear and accounted for. MSDN Support admitted it was a limitation but felt justified in not explaining it because it seemed a bizarre thing to want to do -- to them, a separate domain name implies a separate web-site, and thus the only sensible solution is to house them as separate sites in IIS and use virtual directories for the shared files and configuration settings. From our point of view, we have one principal site with various "skins": each has its own customisable style, appearance and features but all of them run from the same code base and use the same config settings. Therefore a more natural design to us was to run them as sub-directories in IIS; and indeed this works perfectly if you don't try to address them individually (i.e., with separate domains). Since that is a commercial consideration (our clients require their sites to be addressable with their choice of domain names) rather than a design consideration, it seems that ours is in fact a viable use-case that has been missed.

like image 125
Ed Graham Avatar answered Sep 27 '22 22:09

Ed Graham