Search code examples
viewasp.net-mvc-3razorpartialviewbag

Modifying MVC 3 ViewBag in a partial view does not persist to the _Layout.cshtml


I am using MVC 3 with the Razor view engine. I want to set some values in the ViewBag inside a Partial View and want retrieve those values in my _Layout.cshtml. For example, when you setup a default ASP.NET MVC 3 project you get a _Layout.cshtml file in the "/Views/Shared" folder. In that _Layout.cshtml the Page Title is set like this:

<title>@ViewBag.PageTitle</title>

Then in "/Views/Home/About.cshtml" view the contents of the ViewBag are modified:

@{
    ViewBag.Title = "About Us";
}

This works fine. When the About view is rendered the page title is "About Us". So, now I want to render a Partial view inside my About view and I want to modify the ViewBag.Title inside my Partial view. ("/Views/Shared/SomePartial.cshtml")

@Html.Partial("SomePartial")

In this Partial view I have this code:

@{
    ViewBag.Title = "About Us From The Partial View";
}

When I debug this code I see the ViewBag.Title get set to "About Us" and then in the Partial view I see it get reset to "About Us From The Partial View", but when the code hits the _Layout.cshtml it goes back to "About Us".

Does this mean that if the contents of the ViewBag are modified in a Partial view, those changes will not appear(be accessible) in the main view (About.cshtml) or the _Layout.cshtml?

Thanks in advance!


Solution

  • I also had this problem, and couldn't find any neat and obvious solution.

    The solution I came up with was to implement an Html extension method that returns a 'PageData' class that you define, containing whatever data you need:

        [ThreadStatic]
        private static ControllerBase pageDataController;
        [ThreadStatic]
        private static PageData pageData;
    
        public static PageData GetPageData(this HtmlHelper html) {
            ControllerBase controller = html.ViewContext.Controller;
            while (controller.ControllerContext.IsChildAction) {
                controller = controller.ControllerContext.ParentActionViewContext.Controller;
            }
            if (pageDataController == controller) {
                return pageData;
            } else {
                pageDataController = controller;
                pageData = new PageData();
                return pageData;
            }
        }
    

    It finds the top-level controller for the current request, and returns the same PageData object every time the method is called within the same HTTP request. It creates a new PageData object the first time it is called in a new HTTP request.