Best Practices for Implementing Two Layout Variants Based on User Authentication in Kentico 13 MVC

Florian Lauenstein asked on August 12, 2023 18:34

Hello Kentico Community,

I am currently working on a Kentico 13 MVC application that essentially has two "homepages" depending on whether a user is logged in or not. I have set up Content-Based Routing in Kentico, and the majority of the system is working as intended. However, I am facing a challenge with the initial request to the root ("/") when the user is authenticated.

Here's my code in

_ViewStart.cshml

@{
    if (Context.User.Identity?.IsAuthenticated ?? false)
    {
        Layout = "~/Views/Shared/_DashboardLayout.cshtml";
    }
    else
    {
        Layout = "~/Views/Shared/_HomeLayout.cshtml";
    }
}

Everything works perfectly, except the first request to "/" when redirected to "/{culture}". During this first request, I get an exception:

InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'Kentico.PageBuilder.Web.Mvc.ComponentDefaultViewModel1[Generic.Features.Home.HomePageTemplateProperties]', but this ViewDataDictionary instance requires a model item of type 'Generic.Features.Dashboard.DashboardViewModel'.

As I understand, this is happening because of the model type expected during the initial request, but I'm at a loss as to how to work around this situation.

The core question here is: What changes do I need to make to ensure that the initial "/" calls the "/Dashboard" controller when the user is authenticated, and not the via the Kentico PageBuilder?

I would appreciate insights into the best practices for handling this specific scenario, and any guidance you can provide to help resolve this challenge.

I am using K13.0.115, MVC, .Net 6 with Content Based Routing.

Thank you for your support and looking forward to your valuable feedback!

Best Regards, Florian

Recent Answers


Jono Rickard answered on September 26, 2023 04:42

Heya Florian,

Id need a bit more info to diagnose this specific error - but generally that exception means kentico has the deafult ComponentDefaultViewModel<HomePage> and expects your view to have @model ComponentDefaultViewModel<HomePage>, but your view instead has a @model DashboardViewModel

There are a few ways you couldve set this up, but for this case I would reccommend doing the is logged in/not logged in using a controller eg HomePageController for the page template and registering it with

[assembly: RegisterPageRoute(HomePage.CLASS_NAME, typeof(HomePageController))]

This links any urls that resolve to the home page in the content tree to the Index() method of your HomePageController.

From there you can check if there is a logged in user, and Redirect to the Dashboard url.

Best pratice here is to not use static urls in the BE - so that the content tree is fully functional - so in this case HomePageController.Index() could look something like this;

[assembly: RegisterPageRoute(HomePage.CLASS_NAME, typeof(HomePageController))]

public class HomePageController
{
    //Used to get the current page context
    private readonly IPageDataContextRetriever pageDataContextRetriever;

    //Used to convert a TreeNode instance into its url in the content tree
    private readonly IPageUrlRetriever pageUrlRetriever;

    //Standard way to inject the httpcontext into the controller
    private readonly IHttpContextAccessor httpContextAccessor;

    //Used to make a query to the Kentico Tree db to retrieve a TreeNode (in our case a Dashboard page)
    private readonly IPageRetriever pageRetriever;

    public HomePageController(IPageDataContextRetriever pageDataContextRetriever, IPageUrlRetriever pageUrlRetriever, IHttpContextAccessor httpContextAccessor, IPageRetriever pageRetriever){
        this.pageDataContextRetriever = pageDataContextRetriever;
        this.pageUrlRetriever = pageUrlRetriever;
        this.httpContextAccessor = httpContextAccessor;
        this.pageRetriever = pageRetriever;
    }

    [HttpGet]
    public IActionResult Index(){
        // Check the request is actually for the page type we expect
        if (pageDataContextRetriever.TryRetrieve<HomePage>(out var data) 
           && data?.Page is HomePage currentPage)
        {
            if (httpContextAccessor.HttpContext?.User?.Identity?.IsAuthenticated ?? false)
            {
                //User is logged in -> redirect to the Dashboard page type
                // We need to find the Dashboard page TreeNode we want to redirect to 
                // Im presuming theres just a single Dashboard page on the site here. 
                var dashboardTreeNode = pageRetriever.Retrieve<Dashboard>().FirstOrDefault(); 

                // Then ask kentico what the url it has is
                var dashboardURL = mPageUrlRetriever.Retrieve(dashboardTreeNode).AbsoluteUrl;

                // Then use the standard redirect 
                return Redirect(dashboardURL);
            }
            else
            {
                return View(new HomePageViewModel(currentPage)); //return to the home page view 
            }
        }
    }
}
0 votesVote for this answer Mark as a Correct answer

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