BasePageTemplateController is breaking another page

Hosam Abdeltawab asked on September 4, 2020 18:32

I created page templates and added a base controller to determine which page template it is and route to the correct view. However, it is breaking another page I had before (samplePage). I added a route config for routing the selected page templates and that broke my previous added sample page. When I remove the "Templates" route that I added the sample page works but the templates don't and vice versa. Here is my code:

BasePageTemplateController

    using AE.Web.Gwic.Models.PageTemplates;
    using CMS.DocumentEngine;
    using Kentico.PageBuilder.Web.Mvc;
    using Kentico.PageBuilder.Web.Mvc.PageTemplates;
    using Kentico.Web.Mvc;
    using System.Linq;
    using System.Web.Mvc;

    namespace AE.Web.Gwic.Controllers
    {
        public class BasePageTemplateController : Controller
        {
            /// <summary>
            /// A GET action displaying the page where you wish to use page templates.
            /// </summary>
            /// <param name="pageAlias">Page alias of the displayed page.</param>
            public ActionResult Index(string pageAlias)
            {
                // Retrieves the page from the Kentico database
                TreeNode page = DocumentHelper.GetDocuments()
                    .WhereEquals("NodeAlias", pageAlias)
                    .OnCurrentSite()
                    .TopN(1)
                    .FirstOrDefault();

                // Returns a 404 error when the retrieving is unsuccessful
                if (page == null)
                {
                    return HttpNotFound();
                }

                // Initializes the page builder with the DocumentID of the page
                HttpContext.Kentico().PageBuilder().Initialize(page.DocumentID);

                // Returns a TemplateResult object, created with an identifier of the page as its parameter
                // Automatically initializes the page builder feature for any editable areas placed within templates
                return new TemplateResult(page.DocumentID);
            }
        }
    }

SampleController

    using CMS.DocumentEngine.Types.SampleNamespace;
    using CMS.SiteProvider;
    using Kentico.PageBuilder.Web.Mvc;
    using Kentico.Web.Mvc;
    using System.Web.Mvc;

    namespace AE.Web.Gwic.Controllers
    {
        public class SampleController : Controller
        {
            [HttpGet]
            [Route("/Sample")]
            public ActionResult Index()
            {
                Sample pageData = SampleProvider.GetSample("/Sample", "en-us", SiteContext.CurrentSiteName)
                    .Columns("SampleID", "SampleHeader", "SampleText");

                // Returns a 404 error if retrieval is unsuccessful
                if (pageData == null)
                    return HttpNotFound();

                // Initializes the page builder with the DocumentID of the page
                HttpContext.Kentico().PageBuilder().Initialize(pageData.DocumentID);

                return View(pageData);
            }
        }
    }

RouteConfig

    using Kentico.Web.Mvc;
    using System.Web.Mvc;
    using System.Web.Routing;

    namespace AE.Web.Gwic
    {
        public class RouteConfig
        {
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

                // Maps routes to Kentico HTTP handlers and features enabled in ApplicationConfig.cs
                // Always map the Kentico routes before adding other routes. Issues may occur if Kentico URLs are matched by a general route, for example images might not be displayed on pages
                routes.Kentico().MapRoutes();

                routes.MapRoute(
                    name: "Templates",
                    url: "{pageAlias}",
                    defaults: new { controller = "BasePageTemplate", action = "Index" }
                    );

                routes.MapRoute(
                    "Default",
                    "{controller}/{action}/{id}",
                    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
                );
            }
        }
    }

What might I do to fix this issue, and get both the sample page and page templates to work properly?

Correct Answer

Dmitry Bastron answered on September 7, 2020 11:28

This simpliest implementation should work, route registration:

routes.MapRoute(
    name: "Templates",
    url: "{pageAlias}",
    defaults: new { controller = "BasePageTemplate", action = "Index" }
    constraints: new { DynamicTemplate = new DynamicTemplateConstraint() }
);

routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

And the constraint:

public class SiteCultureConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        return !String.Equals(route.Url, "sample", StringComparison.OrdinalIgnoreCase);
    }
}

However, I wouldn't say this is a good approach as this looks to be too specific about route names. Please consider using some of the dynamic routing implementations instead, like this one by Trevor Fayas.

0 votesVote for this answer Unmark Correct answer

Recent Answers


Dmitry Bastron answered on September 4, 2020 18:50

Hi Hosam,

This is the expected behaviour. When you added "Templates" route before the default one it got a higher priority. It means that when you are trying to resolve "/sample" URL it tries to find a page with this alias and returns template for it. What you need to do is to implement a routing constraint where you can check whether this route can be applied or not. You can see an example of constraint here or on Dancing Goat sample site.

0 votesVote for this answer Mark as a Correct answer

Hosam Abdeltawab answered on September 4, 2020 18:57

How would the constraint look like? Would I just create a constraint to check if the route has /sample then it routes to SampleController else it routes to the baseTemplate controller?

0 votesVote for this answer Mark as a Correct answer

   Please, sign in to be able to submit a new answer.