sitefinitysitefinity-10

Access Controls collection at MVC template level Sitefinity


I need to remove an object from the PageHandler Header Controls collection in my page template.

I can use the below script to do so at the widget view level, however the one I need to remove has not yet been added at that point, so I need to move it right before it's consumed.

The only accessible place for it that I could find is in my template file - right before @Html.Section("head"). I'm trying to remove the default canonical URL for this template only (some crazy routing stuff going on in this site... don't ask).

    var pageHandler = this.ViewContext.HttpContext.Handler.GetPageHandler();
    foreach (var c in pageHandler.Header.Controls)
    {
        if (c != null && c is System.Web.UI.HtmlControls.HtmlLink)
        {
            System.Web.UI.HtmlControls.HtmlLink mylink = (System.Web.UI.HtmlControls.HtmlLink)c;
            if (mylink.Attributes["rel"] == "canonical")
            {
                pageHandler.Header.Controls.Remove(mylink);
            }
        }
    }

When I try to use this in the template file inside the <head> tag pageHandler.Header is null.

1 - Am I accessing this object in the wrong way for this particular template level? If so, what's the proper object reference?

2 - Is it simply not set yet because of some behind-the-scenes page construction order in Sitefinity? If so, where could/should I handle accessing this object?

3 - Something else is going on entirely?


I AM NOT ASKING HOW TO FIX A NULL REFERENCE EXCEPTION

I understand that the object is null and am trying to find where in the Sitefinity viewmodel at this level this data might be found.


Solution

  • The canonical url is set in Page_PreRenderComplete event which fires after your code in the view has executed.

    What I would do is create a new widget, e.g. CanonicalUrlRemover.

    In its Index method find the Page object and subscribe to its PreRenderComplete event. Then in the event handler remove the canonical url.

    public ActionResult Index()
    {
       var page = HttpContext.CurrentHandler.GetPageHandler();
    
       page.PreRenderComplete += Page_PreRenderComplete;            
    
       return new EmptyResult();
    }
    
    private void Page_PreRenderComplete(object sender, System.EventArgs e)
    {
       var page = sender as System.Web.UI.Page;
       if (page != null)
       {
           var headerControls = page.Header.Controls;
           foreach (var c in headerControls)
           {
               if (c != null && c is System.Web.UI.HtmlControls.HtmlLink)
               {
                  System.Web.UI.HtmlControls.HtmlLink mylink = (System.Web.UI.HtmlControls.HtmlLink)c;
                if (mylink.Attributes["rel"] == "canonical")
                {
                    headerControls.Remove(mylink);
                }
            }
          }
       }
    }
    

    Just drop the widget in this particular page template and you are good to go.