lørdag den 23. august 2014

Automatic Multisite Handling By Traversing Sitecore Tree

Add automatic multisite handling to your Sitecore site by traversing the Sitecore Tree to find the available sites. You can decide to use the site name as subdomain or you can specify a hostName in a Sitecore field on the site-item.


 

 

 

 

Web.config changes

Adding a config section for configuring the multisite handler.

 <configSections>  
      <section name="Netmester.ItemResolver" type="Netmester.ItemResolver.Configuration, Netmester.ItemResolver"/>  
 </configSections>  
 <Netmester.ItemResolver SitecoreWebSiteName="subsites" UrlSyntax="{$}.mydomain.dk|www.{$}.mydomain.dk" HostNameField="hostNames" TargetHostName="targetHostName" />  

  • SitecoreWebSiteName -  The name of the site defined in tag in web.config. Is used as template when the sites are created.
  • UrlSyntax - Specifies the syntax used as hostName for each site created. 
  • HostNameField - Specifies a field on the site-element that should be used as hostName. Pipes can be used.
  • TargetHostName - Specifies a field on the site-element that should be used as targetHostName. If none is specified the first one defined as hostName is used.

Override the standard sitecore siteprovider.

 <siteManager defaultProvider="config">  
      <providers>  
           <clear/>  
           <add name="config" type="Netmester.ItemResolver.SiteProvider, Netmester.ItemResolver" siteList="sites" checkSecurity="false"/>  
      </providers>  
 </siteManager>  

Code

Configuration class

Class associated with the config section defined in web.config



 using System;  
 using System.Collections.Generic;  
 using System.Text;  
 using System.Configuration;  
   
 namespace Netmester.ItemResolver  
 {  
  class Configuration : ConfigurationSection  
  {  
   
 #region Properties  
   /// <summary>  
   /// Gets the SitecoreWebSiteName setting.  
   /// </summary>  
   [ConfigurationProperty("SitecoreWebSiteName", IsRequired = true)]  
   public string SitecoreWebSiteName  
   {  
    get { return (string)base["SitecoreWebSiteName"]; }  
   }  
   Expand
   /// <summary>  
   /// Gets UrlSyntax setting  
   /// </summary>  
   [ConfigurationProperty("UrlSyntax", IsRequired = true)]  
   public string UrlSyntax  
   {  
    get { return (string)base["UrlSyntax"]; }  
   }  

   /// <summary>  
   /// Gets field name to find hostname in  
   /// </summary>  
   [ConfigurationProperty("HostNameField")]  
   public string HostNameField  
   {  
     get { return (string)base["HostNameField"]; }  
   }  
   
   /// <summary>  
   /// The templatename of subsites if they are located below subfolders  
   /// </summary>  
   [ConfigurationProperty("SiteTemplateName")]  
   public string SiteTemplateName  
   {  
     get { return (string)base["SiteTemplateName"]; }  
   }  
   
   /// <summary>  
   /// Gets the sub item name  
   /// </summary>  
   [ConfigurationProperty("SitecoreSubItem")]  
   public string SitecoreSubItem  
   {  
     get { return (string)base["SitecoreSubItem"]; }  
   }  
   
   
   /// <summary>  
   /// Gets the TargetHostName  
   /// </summary>  
   [ConfigurationProperty("TargetHostName")]  
   public string TargetHostName  
   {  
     get { return (string)base["TargetHostName"]; }  
   }  
   
   /// <summary>  
   /// Gets the StartItem fieldname  
   /// </summary>  
   [ConfigurationProperty("StartItem")]  
   public string StartItem  
   {  
     get { return (string)base["StartItem"]; }  
   }  
   
   
   public static Netmester.ItemResolver.Configuration GetConfiguration()  
   {  
     return System.Configuration.ConfigurationManager.GetSection("Netmester.ItemResolver")  
        as Netmester.ItemResolver.Configuration;  
   }  
   
 #endregion  
    
  }  
 }  
   

SiteProvider class

Handles the site-creation on startup and serves the sites to whom asks for it.

 using System;  
 using System.Collections.Generic;  
 using System.Collections.Specialized;  
 using System.Globalization;  
 using System.Linq;  
 using Sitecore.Data.Items;  
 using Sitecore.Sites;  
 using Netmester.ExtensionMethods;  
   
 namespace Netmester.ItemResolver  
 {  
   public class SiteProvider : ConfigSiteProvider  
   {  
     internal static Dictionary<string, Site> _customSites;  
   
     Configuration _c = Configuration.GetConfiguration();  
   
     public override void Initialize(string name, NameValueCollection config)  
     {  
       Log(String.Format("Initializing, Name: {0}", name), false);  
       base.Initialize(name, config);  
       Initialize();  
     }  
     Expand
     private void Initialize()  
     {  
       _customSites = new Dictionary<string, Site>();  
       Log("SitecoreWebSiteName: " + _c.SitecoreWebSiteName);  
       Sitecore.Data.Database web = Sitecore.Configuration.Factory.GetDatabase("web");  
   
       if (web == null)  
       {  
         Log("Cant find web database", true);  
         return;  
       }  
   
       var result = base.GetSites();  
       Site site = result.Where(x => x.Name.ToLower() == _c.SitecoreWebSiteName.ToLower()).SingleOrDefault();  
       if (site == null)  
       {  
         Log("Cant find SitecoreWebSiteName", true);  
         return;  
       }  
   
       String path = site.Properties["rootPath"] + site.Properties["startItem"];  
       path = path.Replace("//", "/");  
       Item root;  
       using (new Sitecore.SecurityModel.SecurityDisabler())  
         root = web.GetItem(path);  
   
       if (root == null)  
       {  
         Log("Rootpath cant be found, " + path, true);  
         return;  
       }  
       String[] hosts = _c.UrlSyntax.Split('|').Where(x => x.Trim().Length > 0).ToArray();  
   
       Sitecore.Collections.StringDictionary dic = new Sitecore.Collections.StringDictionary();  
   
       Log("Properties used as site template:");  
   
       foreach (String key in site.Properties.Keys)  
       {  
         dic.Add(key, site.Properties[key]);  
         Log("Property: " + key + ", " + dic[key]);  
       }  
   
       Log("Starting iterating subsites");  
       using (new Sitecore.SecurityModel.SecurityDisabler())  
       {  
         var list = root.Children.OfType<Item>().ToList();  
   
         if( !String.IsNullOrEmpty(_c.SiteTemplateName) )  
         {  
           list = SubsiteItems(root, _c.SiteTemplateName);                
         }  
         IdnMapping idn = new IdnMapping();  
   
         foreach (Item subsite in list)  
         {  
           try  
           {  
             int count = 0;  
   
             // We dont split the hosts up  
             // we only create one site pr. hosts in web.config (is overwritten if hostNameField is typed  
             String host = hosts.Join("|") ;  
               
             //foreach (String host in hosts)  
             {  
               String siteName = "_" + subsite.Name + (count++ > 0 ? count.ToString() : "");  
   
               // Need new instance for each site  
               dic = new Sitecore.Collections.StringDictionary();  
   
               foreach (String key in site.Properties.Keys)  
               {  
                 dic.Add(key, site.Properties[key]);  
               }  
               String hostName = "";  
               if (!String.IsNullOrEmpty(_c.HostNameField))  
               {  
                 if (subsite.Fields[_c.HostNameField] != null)  
                   hostName = subsite[_c.HostNameField];  
                 else  
                   Log("Cant find the host name field on the subsite, " + subsite.Name, true);  
               }  
               
               if (hostName == "")  
                 hostName = host.Replace("{$}", subsite.Name);  
   
               // If nothing is defined we dont do anything  
               if (String.IsNullOrEmpty(hostName))  
               {  
                 Log("No content in UrlSyntax or hostNameField therefor no site created for, " + subsite.Name, false);  
                 continue;  
               }  
   
               String targetHostName = "";  
               if (!String.IsNullOrEmpty(_c.TargetHostName))  
               {  
                 if (subsite.Fields[_c.TargetHostName] != null)  
                   targetHostName = subsite[_c.TargetHostName];  
                 else  
                   Log("Cant find the targetHostname name field on the subsite, " + subsite.Name, true);  
               }  
   
               // If no targetHostname we use the first defined hostname  
               if ( String.IsNullOrEmpty(targetHostName) )  
                 targetHostName = hostName.Split('|').First();   
               
               String startItem = "/";  
               String rootPath = path;  
               if (!String.IsNullOrEmpty(_c.SitecoreSubItem))  
               {  
                 rootPath = subsite.Paths.FullPath;  
                 startItem += _c.SitecoreSubItem;  
               }  
               else  
               {  
                 if (!String.IsNullOrEmpty(_c.SiteTemplateName))  
                   rootPath = subsite.Paths.FullPath.Replace("/" + subsite.Name, "");  
                 startItem += subsite.Name;  
               }  
   
               if ( !String.IsNullOrEmpty(_c.StartItem) )  
               {  
                 if (subsite.Fields[_c.StartItem] != null)  
                 {  
                   Guid g = subsite[_c.StartItem].ToGuid();  
   
                   Item i = web.GetItem(new Sitecore.Data.ID(g));                  
                   if ( i != null )  
                   {  
                     String fullPath = i.Paths.FullPath;  
                     startItem = "/" + fullPath.Split('/').Last();   
                     rootPath = i.Paths.FullPath.Replace(startItem, "");   
                   }  
                 }  
                 else  
                   Log("Cant find the startItem name field on the subsite, " + subsite.Name, true);  
               }  
   
                 
               // Convert to puny-code  
               hostName = hostName.Split('|').Select(x => idn.GetAscii(x)).Join("|");  
               targetHostName = idn.GetAscii(targetHostName);  
   
               dic["rootPath"] = rootPath;  
               dic["name"] = siteName;  
               dic["hostName"] = hostName;  
               dic["startItem"] = startItem;  
               
               if( !String.IsNullOrEmpty(targetHostName) )   
                 dic["targetHostName"] = targetHostName;  
   
   
               if( !_customSites.ContainsKey(siteName) )   
               {  
                 Log(String.Format("Site added, siteName: {0}, rootPath: {1}, startItem: {3}, hostName: {2}, targetHostName: {4}",  
                   dic["name"], dic["rootPath"], dic["hostName"], dic["startItem"], dic["targetHostName"]));  
                 _customSites.Add(siteName, new Site(siteName, dic));  
               }  
               else  
                 Log(String.Format("Site NOT added due to already present i collection, siteName: {0}, rootPath: {1}, startItem: {3}, hostName: {2}, targetHostName: {4}",  
                          dic["name"], dic["rootPath"], dic["hostName"], dic["startItem"], dic["targetHostName"]), true);  
   
               // If a hostnamefield is specified and used we break because we dont want to use the UrlSyntax in web.config and the hostNames from sitecore at the same time  
               // If not breaking we create all the sites twice resulting in double cache  
               //if ( !String.IsNullOrEmpty(subsite[_c.HostNameField]) )  
               //  break;  
   
             }  
           }  
           catch (Exception ex)  
           {  
             Log("Subsite failed: " + subsite.Paths.ContentPath + ", " + ex.ToString(), true);   
           }  
         }  
       }  
       Log("Initializing end");  
     }  

     internal static void Log(String msg)  
     {  
       Log(msg, false);  
     }  
     private static void Log(String msg, Boolean isError)  
     {  
       // Log it  
     }  
     List<Item> SubsiteItems(Item parent, String templateName)  
     {  
       List<Item> list = new List<Item>();  
   
       foreach (Item i in parent.Children)  
       {  
         if (i.TemplateName.ToLower() == templateName.ToLower())  
           list.Add(i);  
         else  
           list.AddRange(SubsiteItems(i, templateName));  
       }  
   
       return list;  
   
     }  
   
     private Dictionary<string, Site> CustomSites  
     {  
       get  
       {  
         if (_customSites == null)  
           Initialize();  
         return _customSites;  
       }  
     }  
     public override SiteCollection GetSites()  
     {  
       SiteCollection result = new SiteCollection();  
       Log("GetSites");  
       result.AddRange(this.CustomSites.Values);  
       Log(String.Format("GetSites, CustomSitesCount: {0}", this.CustomSites.Count));  
       result.AddRange(base.GetSites());  
       return result;  
     }  
   
     public override Site GetSite(string siteName)  
     {  
       Log("GetSite, " + siteName);  
       var site = base.GetSite(siteName);  
       return site ?? (_customSites.ContainsKey(siteName) ? _customSites[siteName] : null);  
     }  
   }  
 }  
   

Ingen kommentarer:

Send en kommentar