Search code examples
c#razorasp.net-mvc-5partial-viewsasp.net-mvc-controller

How to get value of the default layout from _ViewStart.cshtml in MVC/Razor


I have an extension methods for MVCs Controller class that needs to know what the current default layout file is (i.e. the value from _ViewStart.cshtml).

The code is in a library, so I only have the controller to start from. The code below basically allows any controller action to always return a PartialPage, but conditionally assigns the default layout layout (making it a full View) if it was not in response to an Ajax request (e.g. to see the entire page for debugging).

e.g.

public static void RenderMode(this Controller controller)
{
     if (!controller.Request.IsAjaxReuest())
     {
         controller.ViewBag.Layout = ????????;
     }
}

So the question is, how do you get at the default layout page value from code?


Solution

  • According to the comment from Andreas (thanks), the required setting is buried away in the RazorViewEngine class and is not accessible.

    Update Sep 2015 - New Solution!

    We recently found a better way to do this, without the invasive changes to any action code.

    Steps:

    • Inherit all controllers from a common BaseController class.
    • Add an OnActionExecuting override method to the BaseController.
    • Call RenderMode() from inside that method - so this will happen for all requests, before the action gets called.
    • Change RenderMode() to set ViewBag.Layout = null for Ajax page requests.
    • Inside _ViewStart.cshtml add code to set the layout to a ViewBag value.

    BaseController.cs - RenderMode()

    public void RenderMode(string layout)
    {
        if (IsPartialPage)
        {
            // Wipe any existing layout page
            ViewBag.Layout = null;
            return;
        }
        ViewBag.Layout = layout;
    }
    

    ViewStart.cshtml

    @{
        Layout = (string)ViewContext.Controller.ViewBag.Layout;
    }
    

    The end result is that you can return a View() or a PartialView() as normal and the view will be rendered as a full or partial view based instead on the "ajax" check done before the action executes. This has simplified our websites significantly as we can use more of the standard scaffolded code as-is.


    Previous solution (now obsolete)

    My workaround is therefore to pass a default layout to the RenderMode extension method:

    i.e.

    public static void RenderMode(this Controller controller, layout)
    {
         if (!controller.Request.IsAjaxReuest())
         {
             controller.ViewBag.Layout = layout;
         }
    }
    

    and call from any controller like this (or using a constant known to the app):

    public ActionResult SomeAction()
    {
        var vm = new SomeViewModel();
        RenderMode("~/views/shared/_MainLayout.cshtml");
        return PartialView(vm);
    }
    

    The end result is a partial view when called from Ajax or a full view, using _mainLayout.cshtml, if called directly.