Multiple Url Single Installation of Composite C1

David Robertson
WRITTEN BY  David Robertson- 30 June 2011

For those that do not know Composite C1 is an Open Source Content Management System (CMS) written for ASP.NET.

If ever you have wondered how to have one physical representation of your Composite C1 site on your server, but serve multiple Sites then this is how I did it...It might be necessary to use this scenario in order to save you having to add all those useful tweaks and reusable function calls to every installation of Composite you might otherwise need.

Note: I have not catered for secure sites as yet. But this should not be difficult to implement in Code Sample 3. You would just need to interrogate the incoming Url to see if it is https or not then select the correct redirect mode.

You will need to set up string array containing all the domains that will be hosted similar to that in Code Sample 1. NB: Leave off the www. because this may or may not be included when the surfer enters the Url.

Code Sample 1:

///
/// The domains that Composite C1 auto navigator is designed to work with.
///
public static string[] _Domains = new string[] { "dare-it.com", "ibuyzit.robertsonweb.me.uk" };

You will need to set up an enum with the same number of elements as are in the string array from Code Sample 1. Note that the enums must match the names of the root pages for each site, also "-" becomes "_".

Code Sample 2:

///
/// These enums represent the Domains served by this Composite C1 instance.
///
public enum Domains 
{ 
  ///
  /// dare-it.com Blog.
  ///
  dare_it, 
  ///
  /// ibuyzit.com customer site.
  ///
  ibuyzit 
}
  

Now for the juicy bit. The engine, so to speak, which makes sure the page matches the domain. There are essentially two sections. The first part handles a domain entry point from default.aspx, the second handles a domain entry point from any other page.

Code Sample 3:

public class Navigation
{
    // Redirects the relevant Url attempt to the correct base domain.
    public static void Redirect(bool lbEndResponse)
    {
        if (HttpContext.Current.Request.Url.AbsoluteUri.ToLower().Contains("default.aspx"))
        {
            // This part handles a domain entry point from default.aspx. This includes the surfer entering the Url only.
            if (HttpContext.Current.Request.Url.AbsoluteUri.ToLower().Contains("localhost"))
            {
                // If localhost (i.e. debug local) go to a the root page of the site you are currently debugging.
                HttpContext.Current.Response.Redirect("~/ibuyzit.aspx", lbEndResponse);
                return;
            }
            else
            {
                // Let's go through each of the domains in the enum
                foreach (Heron.App_Code.Enums.Domains leDomain in Enum.GetValues(typeof(Heron.App_Code.Enums.Domains)))
                {
                    // Let us establish the domain we are attempting to access in order to determine the correct root webpage to display.
                    if (HttpContext.Current.Request.Url.AbsoluteUri.ToLower().Contains(Heron.App_Code.Globals._Domains[(int)leDomain]))
                    {
                        // we need to redirect to the relevant root webpage.
                        HttpContext.Current.Response.Redirect("~/" + leDomain.ToString().Replace("_", "-") + ".aspx", lbEndResponse);
                        return;
                    }
                }
            }
        }
        else
        {
            // Here we are essentially making sure that the correct root domain is being used for the page being served. If not then it is requested correctly.
            if (!HttpContext.Current.Request.Url.AbsoluteUri.ToLower().Contains("localhost"))
            {
                // Let's go through each of the domains in the enum
                foreach (Heron.App_Code.Enums.Domains leDomain in Enum.GetValues(typeof(Heron.App_Code.Enums.Domains)))
                {
                    if (HttpContext.Current.Request.Url.AbsoluteUri.ToLower().Contains("/" + leDomain.ToString().ToLower().Replace("_", "-") + "/") && !HttpContext.Current.Request.Url.AbsoluteUri.ToLower().Contains(Heron.App_Code.Globals._Domains[(int)leDomain]))
                    {
                        // If we are currently trying to access a sub page
                        HttpContext.Current.Response.Redirect("http://" + Heron.App_Code.Globals._Domains[(int)leDomain] + "/" + leDomain.ToString().ToLower().Replace("_", "-") + "/" + HttpContext.Current.Request.Url.PathAndQuery, lbEndResponse);
                        return;
                    }
                    else if (HttpContext.Current.Request.Url.AbsoluteUri.ToLower().Contains(leDomain.ToString().ToLower().Replace("_", "-") + ".aspx") && !HttpContext.Current.Request.Url.AbsoluteUri.ToLower().Contains(Heron.App_Code.Globals._Domains[(int)leDomain]))
                    {
                        // If we are currently trying to access the root page
                        HttpContext.Current.Response.Redirect("http://" + Heron.App_Code.Globals._Domains[(int)leDomain] + "/" + leDomain.ToString().ToLower().Replace("_", "-") + ".aspx" + ((!string.IsNullOrEmpty(HttpContext.Current.Request.Url.Query)) ? "?" + HttpContext.Current.Request.Url.Query : string.Empty), lbEndResponse);
                        return;
                    }
                }
            }
        }
    }
}
    

Below is a snippet from the default.aspx of the main site. The line in Red is the call to the Redirect function in Code Sample 3. This ensures that regardless of page being called up the correct domain is selected for it and from that point on the correct content is filtered from ALL the content contained within the Composite C1 installation.

Code Sample 4:

void Page_Init(object sender, EventArgs e)
{
    Heron.Library.Composite.Navigation.Redirect(true);
    if (SystemSetupFacade.IsSystemFirstTimeInitialized == false)
    {
        Response.Redirect(string.Format("Composite/top.aspx{0}", RuntimeInformation.IsDebugBuild ? "?mode=develop" : ""));
    }

    using (DataConnection dataConnection = new DataConnection(DataLocalizationFacade.DefaultLocalizationCulture))
    {
        SitemapNavigator sitemapNavigator = new SitemapNavigator(dataConnection);
        PageNode homePageNode = sitemapNavigator.GetPageNodeByHostname(Request.Url.Host);

        if (homePageNode != null)
        {
            Response.AddHeader("Location", homePageNode.Url);
            Response.StatusCode = 301; //  "Moved Permanently"
            HttpContext.Current.ApplicationInstance.CompleteRequest();
        }
    }
}
          

Code Sample 5 is taken from the CompositeC1Page.cs in the Core library. The line in Red below is the call to Redirect in Code Sample 3. We do not want to process the rest of the page (hence passing true to Redirect) if a Redirect occurs as it will get reprocessed correctly on the way in again when the correct Url has been selected.

Code Sample 5:

protected override void OnPreInit(EventArgs e)
{
    Heron.Library.Composite.Navigation.Redirect(true);
    base.Theme = "nopClassic";
    var rq = RequestInfo.Current;

    if (rq.IsPreview)
    {
        Document = (IPage)Cache.Get(rq.PreviewKey + "_SelectedPage");
        _url = new PageUrl(PublicationScope.Unpublished, CultureInfo.CreateSpecificCulture(Document.CultureName), Document.Id);
        _dataScope = new DataScope(DataScopeIdentifier.FromPublicationScope(_url.PublicationScope), _url.Locale);
    }
    else
    {
        _profilingEnabled = UserValidationFacade.IsLoggedIn() && Request.Url.OriginalString.Contains("c1mode=perf");
        if (_profilingEnabled)
        {
            Profiler.BeginProfiling();
            _pagePerfMeasuring = Profiler.Measure("C1 Page");
        }

        _url = PageUrl.Parse(Context.Request.Url.OriginalString, out _foreignQueryStringParameters);
        _dataScope = new DataScope(DataScopeIdentifier.FromPublicationScope(_url.PublicationScope), _url.Locale);
        Document = PageManager.GetPageById(_url.PageId);

        _cacheUrl = Request.Url.PathAndQuery;
        RewritePath();
    }

    ValidateViewUnpublishedRequest();

    if (Document == null)
    {
        throw new HttpException((int)HttpStatusCode.NotFound, "Page not found");
    }

    InitializeCulture();

    IPageTemplate template = null;
    using (var conn = new DataConnection())
    {
        template = conn.Get<IPageTemplate>().Single(t => t.Id == Document.TemplateId);
    }

    string masterFile = String.Format("~/App_Data/PageTemplates/{0}.master", template.Title);
    if (HostingEnvironment.VirtualPathProvider.FileExists(masterFile))
    {
        AppRelativeVirtualPath = "~/";
        MasterPageFile = masterFile;
    }

    if (!rq.IsPreview)
    {
        _cacheUrl = Request.Url.PathAndQuery;

        var cachePolicy = Context.Response.Cache;
        cachePolicy.SetVaryByCustom("C1Page_ChangeDate");
        cachePolicy.SetExpires(DateTime.Now.AddSeconds(60));
        cachePolicy.VaryByParams["*"] = true;

        RewritePath();
    }

    base.OnPreInit(e);
}
          
Bookmark and Share
Write Your Comment
  • Captcha image


© 2012 D.A.R. Enterprises. All rights reserved.

Powered By D.A.R. Enterprises

webmaster@dare-it.co.uk