Question

I've been searching for a way to determine the "nesting level" of a view. I've found: Determine view 'nesting level' here on stackoverflow.com. But that only works with RenderAction and only says if it is a child view or not.

What I would like is that layout has level 0, views rendered in layout (e.g. with @RenderBody()) has level 1, views rendered in that view (e.g. with @Html.Partial(...)) has level 2.

For example:

  • _Layout.cshtml (0)
    • _LoginPartial.cshtml (1)
    • Index.cshtml (1)
      • DataTable.cshtml (2)
        • DataHeader.cshtml (3)
        • DataRow.cshtml (3)

Do anyone have a solution for this?

Was it helpful?

Solution

After some investigation I found a static class System.Web.WebPages.TemplateStack that is used when executing views, pushing template on to stack before execution and popping after execution so the size of the stack can be used to determine the level. There is no count variable or any public property/method to get the actual stack. However there is a private method GetStack(HttpContextBase).

I solved it by using reflection and a extension method:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.WebPages;
using System.Reflection;
using System.Collections;

namespace Mollwe.Helpers
{
    public static class TemplateStackLevelAccessor
    {
        private static MethodInfo _getStackMethod;

        public static int GetTemplateLevel(this HtmlHelper htmlHelper)
        {
            return GetTemplateLevel(htmlHelper.ViewContext);
        }

        public static int GetTemplateLevel(this ViewContext viewContext)
        {
            return GetTemplateLevel(viewContext.HttpContext);
        }

        public static int GetTemplateLevel(this HttpContextBase httpContext)
        {
            if (_getStackMethod == null)
            {
                _getStackMethod = typeof(TemplateStack).GetMethod("GetStack", BindingFlags.NonPublic | BindingFlags.Static);
            }

            var stack = _getStackMethod.Invoke(null, new object[] { httpContext }) as Stack<ITemplateFile>;

            return stack.Count - 1;
        }
    }
}

Maybe not the best way but it works. As the stack is used within execution of view it will only work in views or in code called from views.

Dependant on System.Web.WebPages.WebPageBase's implementation of ExecutePageHierarchy() that is called in derived type System.Web.Mvc.WebViewPage which is used in RazorView.RenderView(...).

OTHER TIPS

For anyone looking to do this in ASP.Net Core, you need to implement your own ViewResultExecutor. You can intercept all 'ExecuteAsync()' calls, which get nested, allowing one to build their own nesting level.

See here for more details: Hooking into razor page execution for ASP.Net Core

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top