How to redirect a specific domain to a sublevel page on a different domain using URL Rewrites in IIS7

Anytime I have to look up something twice in three days I figure I might need that info again. Sometimes you have multiple domains pointing to the same site one of which might be a “marketing domain”. Here’s how to redirect a domain request to a page on a different domain.

  • Select URL Rewrite
  • Select Blank rule
  • Enter the pattern
    (.*)

     NOTE: This means any character, any number of repetitions.

  • Expand Conditions if not already expanded and Click “Add”.
  • Enter
     {HTTP_HOST} 

    for “Condtion Input”. (Curly braces are required)

  • Set “Check if input string” to “Matches the Pattern”
  • Pattern
    (?:www.)?domain.com 

    where domain is the domain to redirect. (The part

     (?:www.)? 

    makes www. optional

  • Enter the URL such as
    http://www.newdomain.com/sub/page1.aspx
  • Enter “Redirect” for action
  • Redirect type should be 302 if this is temporary, 301 for permanent redirects. Browsers cache 301 redirects so if it changes in the future, it may take a while for users to know about it.
  • Another way to redirect mobile devices to m. subdomain

    Mortaza Kamal Nourestani posted here a way to ensure that mobile devices are served at a “m.” subdomain site, and that desktop devices are served at the normal domain.
    Here’s my take on that using a resolver in the httprequest pipeline. This only requires adding a class, and .config file with no modifications to existing files. I’ve reused his IsMobileBrowser method.

    using System;
    using System.Linq;
    using System.Web;
    using Sitecore.Pipelines.HttpRequest;
    
    namespace Samples.Extensions.Resolvers
    {
        public class MobileSiteResolver : Sitecore.Pipelines.HttpRequest.SiteResolver
        {
            public override void Process(HttpRequestArgs args)
            {
                string absoluteUri = String.Format("{0}://{1}{2}", HttpContext.Current.Request.Url.Scheme,
                                                           HttpContext.Current.Request.Url.Host,
                                                           HttpContext.Current.Request.RawUrl);
    
                string host = HttpContext.Current.Request.Url.Host;
    
                if (host.StartsWith("m."))
                {
                    if (!IsMobileBrowser(HttpContext.Current))
                    {
                        host = host.Replace("m.", "");
                        absoluteUri = absoluteUri.Replace(HttpContext.Current.Request.Url.Host, host);
                        HttpContext.Current.Response.Redirect(absoluteUri);
                    }
                }
                else
                {
                    if (IsMobileBrowser(HttpContext.Current))
                    {
                        host = String.Format("{0}.{1}", "m", HttpContext.Current.Request.Url.Host);
                        absoluteUri = absoluteUri.Replace(HttpContext.Current.Request.Url.Host, host);
                        HttpContext.Current.Response.Redirect(absoluteUri);
                    }
                }
            }
    
            public static bool IsMobileBrowser(HttpContext context)
            {
                //FIRST TRY BUILT IN ASP.NT CHECK
                if (context.Request.Browser.IsMobileDevice)
                {
                    return true;
                }
                //THEN TRY CHECKING FOR THE HTTP_X_WAP_PROFILE HEADER
                if (context.Request.ServerVariables["HTTP_X_WAP_PROFILE"] != null)
                {
                    return true;
                }
                //THEN TRY CHECKING THAT HTTP_ACCEPT EXISTS AND CONTAINS WAP
                if (context.Request.ServerVariables["HTTP_ACCEPT"] != null &&
                    context.Request.ServerVariables["HTTP_ACCEPT"].ToLower().Contains("wap"))
                {
                    return true;
                }
                //AND FINALLY CHECK THE HTTP_USER_AGENT
                //HEADER VARIABLE FOR ANY ONE OF THE FOLLOWING
                if (context.Request.ServerVariables["HTTP_USER_AGENT"] != null)
                {
                    //Create a list of all mobile types
                    string[] mobiles =
                        {
                            "midp", "j2me", "avant", "docomo",
                            "novarra", "palmos", "palmsource",
                            "240x320", "opwv", "chtml",
                            "pda", "windows ce", "mmp/",
                            "blackberry", "mib/", "symbian",
                            "wireless", "nokia", "hand", "mobi",
                            "phone", "cdm", "up.b", "audio",
                            "SIE-", "SEC-", "samsung", "HTC",
                            "mot-", "mitsu", "sagem", "sony"
                            , "alcatel", "lg", "eric", "vx",
                            "NEC", "philips", "mmm", "xx",
                            "panasonic", "sharp", "wap", "sch",
                            "rover", "pocket", "benq", "java",
                            "pt", "pg", "vox", "amoi",
                            "bird", "compal", "kg", "voda",
                            "sany", "kdd", "dbt", "sendo",
                            "sgh", "gradi", "jb", "dddi",
                            "moto", "iphone"
                        };
    
    
                    //Loop through each item in the list created above
                    //and check if the header contains that text
                    if (mobiles.Any(s => context.Request.ServerVariables["HTTP_USER_AGENT"].ToLower().Contains(s.ToLower())))
                        return true;
    
                }
    
                return false;
            }
        }
    }
    

    To enable this resolver create a config file in /app_config/includes/ such as mobiledeviceresolver.config with these content:

    <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
        <sitecore>
            <pipelines>
                <httpRequestBegin>
                    <processor patch:before="*[@type='Sitecore.Pipelines.HttpRequest.SiteResolver, Sitecore.Kernel']"
                    type="Samples.Extensions.Resolvers.MobileSiteResolver, Logica.Extensions"/>
                </httpRequestBegin>
            </pipelines>
        </sitecore>
    </configuration>
    

    The usual caveats apply, this is untested in a production environment, test throughly before using. It could also be significantly optimized for performance.

    Handy Sitecore Admin URLs

    A while back one of our enterprise Sitecore clients* called in a panic because they could not access the Sitecore desktop. Somehow the English language item had gotten deleted overnight. We told them about the dbbrowser page where they were able to undo the damage. I realized not every Sitecore developer knows all of these so compiled a quick list of handy “secret” admin URLs for Sitecore. When I need one, I need it in a hurry so thought I’d just make a list.
    • Kick users page: /sitecore/shell/Applications/login/users/Kick.aspx
    • DB Browser (when you can’t get to the content editor) /sitecore/admin/dbbrowser.aspx
    • Show Config /sitecore/admin/showconfig.aspx
    • Unlock Admin /sitecore/admin/unlock_admin.aspx
    • Cache /sitecore/admin/cache.aspx
    • Upgrade/Package wizard /sitecore/admin/updateinstallationwizard.aspx
    • Log Viewer /sitecore/shell/applications/reports/logviewer.aspx

    I’ll update as I compile more. Drop me a note if you know of one I missed.

    Paul

    *Obviously can’t name the client but they are part of one of the top three most prestigious Universities in the United States.

    Best practice for managing Rewrite Rules in IIS7

    When moving a client from an old site to a new one, you frequently need to redirect Legacy URLs to new ones to maintain SEO. IIS 7 Rewrite Rules with Rewrite Maps easily accomplish this. A Rewrite Map is simply a subset of a rule with a list of source/destinations. With a bit of massaging, you can take a Excel workbook and export to a map.

    The only problem with IIS rewrites are they are added to the web.config file, which for a Sitecore app is already 4000+ lines. Here’s how to keep it clean:
    Add the section everything inclusive of the <rewrite> tags just before the ending </system.webServer> tag.

    
    <system.webServer>
        {lots of stuff here}
            <rewrite>
                <rewriteMaps configSource="RewriteMaps.config" />
                <rules configSource="RewriteRules.config" />
            </rewrite>
    </system.webServer>
    
    

    Add two files RewriteMaps.config and RewriteRules.config (samples below) to the web root. IIS will save any changes and additions to the external config files instead of the web.config.

    In my starter files (below) are two rewrite maps, Legacy URLs and Marketing URL’s. Legacy would be for the old to new pages which will likely never change, and Marketing rules is for advertising campaigns etc. Keeping them segregated makes updates easier.

    RewriteMaps.config

    <rewriteMaps>
        <rewriteMap name="Legacy URLS">
            <add key="/about_directory.asp" value="/About/Find-an-Office.aspx" />
            <add key="foo" value="bar" />
        </rewriteMap>
        <rewriteMap name="Marketing Rules">
            <add key="/jobs" value="/AboutUs/Careers.aspx" />
        </rewriteMap>
    </rewriteMaps>
    
    

    RewriteRules.config

    <rules>
        <rule name="Redirect rule1 for Legacy URLS">
            <match url=".*" />
            <conditions>
                <add input="{Legacy URLS:{REQUEST_URI}}" pattern="(.+)" />
            </conditions>
            <action type="Redirect" url="{C:1}" appendQueryString="false" />
        </rule>
        <rule name="Rewrite rule1 for Marketing Rules">
            <match url=".*" />
            <conditions>
                <add input="{Marketing Rules:{REQUEST_URI}}" pattern="(.+)" />
            </conditions>
            <action type="Rewrite" url="{C:1}" appendQueryString="false" />
        </rule>
    </rules>
    
    

    One thing to note with this: If you make changes to either of these files manually (in a text editor) it seems that IIS Caches them. So, after your done editing either of those files you need to open the web.config file and re-save it so it forces a refresh.

    Updating DNN to friendly URL’s without hurting your SEO

    I manage several DotNetNuke sites and noticed I had not enabled friendly URL’s on one. This is a typical DNN URL…which is not very intuitive
    http://www.mainesgna.org/AboutMSGNA/SGNAMembershipBenefits/tabid/67/Default.aspx

    Using the Friendly URL feature this is the same page’s URL:
    http://www.mainesgna.org/AboutMSGNA/SGNAMembershipBenefits.aspx

    I wanted to changed the URL scheme, but I didn’t want lose my search rankings so needed to create a rewrite rule to inform search engines with a 302 redirect that the pages have a new home. I use the Helicon product ISAPII Rewrite.

    Here are the steps to do this.

    1. Enable Friendly URL’s in Web.Config. Do this by adding the urlFormat attribute of HumanFriendly to the friendlyUrl node:
            
      
      
            
              
              
            
          
      
    2. Create a Rewrite Rule for isapii Rewrite 2
      RewriteCond Host: www.yourdomain.com
      RewriteRule ^(.*)/tabid/d+/Default.aspx$ $1.aspx [I,RP,L]
    3. The Syntax for Isappi Rewrite 3 is:
    4. RewriteCond %{HTTP:Host} ^www.yourdomain.com$
      RewriteRule ^(.*)/tabid/d+/Default.aspx$ $1.aspx [NC,L,R=301]

      If your not using the lite (free) version of Helicon, and your rewrite file is in the DotNetNuke web root, you can skip the ReWriteCond line.