7

We have converted our app to be ASP.NET Core but I am having a problem with the ViewBag populating correctly. We have the following base controller

public abstract class ControllerBase : Controller
{
    public ControllerBase()
    {
        ViewBag.Title = "MySite";
    }
  ...// lots of other stuff here also
}

All of our other controllers inherit from ControllerBase but by the time we get to the view and use the following

@{
    ViewBag.Title = ViewBag.Title + " - " + Model.PageTitle;
}

But in the view the ViewBag.Title is null. It does not cause an error but we end up with just " - MyPage" rather than "MySite - MyPage" for the browser title.

This all worked correctly in the previous version of .net, just not working now in ASP.NET Core. As I step through the debugger I see that the ControllerBase constructor is being called but the ViewBag data is not persisting.

This leaves me with two questions:

  1. Is there something new/different in ASP.NET Core which changed the scope of the ViewBag?
  2. What is the best way to fix this? (Without adding the value in a bunch of places.)

Edit: I set a debugger stop on the first line of the base controller and stepped through with the ViewBag.Title set as my watch variable. As I step through I can see the value get set and then I move from the base controller to the constructor for the specific action controller. As I step through that constructor the ViewBag.Title is still set. As soon as I hit the first line of the Index() method the ViewBag.Title turns to null.

Edit2: Here is a simple foo project illustrating the issue https://github.com/nurdyguy/ViewBagIssue

KyleMit
  • 30,350
  • 66
  • 462
  • 664
nurdyguy
  • 2,876
  • 3
  • 25
  • 32
  • How about you step through your code and see where `ViewBag.Title` is being overwritten? – CodeCaster Jan 23 '17 at 18:58
  • I don't see it being overwritten anywhere. Anywhere I am (other than in the base controller) the value is null. – nurdyguy Jan 23 '17 at 18:59
  • And you're sure that the controller you're debugging actually inherits `ControllerBase`? There's nothing special about the viewbag, it's just an ordinary property. Inheritance should not break that. – CodeCaster Jan 23 '17 at 19:00
  • I would say please post all relevant code. – christopher clark Jan 23 '17 at 19:03
  • I am positive that all of the controllers in question inherit from the ControllerBase. – nurdyguy Jan 23 '17 at 19:04
  • If I set my debugger on the first line of the constructor for the base controller and set 1 line at a time, the `ViewBag.Title` is set correctly. I added it as a watch variable. As I step through I can see the value is correct, from the base controller to the specific action controller, through the constructor for the action controller, and as soon as it hits the first line of the `Index` method it is suddenly null. – nurdyguy Jan 23 '17 at 19:12
  • Create an example using a new web app project to serve as a baseline. Implement the base controller as you've defined it here and try manipulating the ViewBag. If it doesn't work, you have a small example to share with us. If it does, something else in your code is causing the issue. – Dave Jan 23 '17 at 20:14
  • I'm able to fix this using an `OnActionExecuting` filter but I'm still not sure why it is happening to begin with. As I said, it feels like a weird scoping issue. I dug through about 10 months of issues on the MVC github and nothing jumped out at me. I'll post my solution here in case anyone else comes across the issue. – nurdyguy Jan 23 '17 at 20:36
  • http://stackoverflow.com/questions/34635874/is-viewdata-the-new-standard-over-viewbag-for-asp-net-5-core – Dronacharya Jan 24 '17 at 07:29
  • @Dronacharya Interesting link, thanks. Unfortunately it does nothing for this current issue though. The issue described above occurs whether I use `ViewBag.Title` or `ViewData["Title"]` which isn't surprising given that ViewBag is just a wrapper. If the data isn't there it just isn't there. – nurdyguy Jan 24 '17 at 16:19
  • I'm having the same issue. I encountered the problem while following some Microsoft documentation titled: "Passing Data to View Master Pages" (https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/views/passing-data-to-view-master-pages-cs). The document creates quite the conundrum for someone attempting to apply the provided instructions to an ASP.NET Core MVC project. – T3.0 Feb 05 '18 at 23:16
  • Interesting find. That document is a bit out of date, 10/16/2008, but it would be nice if MS was a bit more consistent. – nurdyguy Feb 06 '18 at 14:52

1 Answers1

8

I still don't know why this is happening but here is a workaround I found. Create an OnActionExecuting filter:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace MyProj.Filters
{
    public class ViewBagFilter : IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            // do something before the action executes
            var controller = context.Controller as Controller;
            controller.ViewBag.Title = "MyPage";
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            // do something after the action executes
        }
    }
}

and add the following to the ConfigureServices method in Startup.cs:

services.AddMvc(options =>
{
    options.Filters.Add(typeof(ViewBagFilter));
    ... // you may have more here...
});

You'll notice the var controller = context.Controller as Controller; has a cast because the controller object on context is an object but it is easy enough to fix.

I'll post back here if I ever find out exactly what caused the issue to begin with. Good hunting!

nurdyguy
  • 2,876
  • 3
  • 25
  • 32
  • Were you ever able to figure out what caused this? I am experiencing the same issue right now... I could go the `IActionFilter` route, but would much prefer to set it in the base controller's constructor since I have a few different base controllers that add different behavior. – e.beyer Dec 19 '17 at 21:25
  • As far as I could tell, it was a bug. We ended up just using the workaround above. At one point I had intended to submit a bug on github but don't think I ever did. – nurdyguy Dec 19 '17 at 21:34
  • 1
    Ah. Looks like there is a bug for it. Stated its by design: https://github.com/aspnet/Mvc/issues/1422#issuecomment-59997202. I'm using your filter solution. Works like a charm. Thanks! – e.beyer Dec 19 '17 at 21:47
  • Good find for the github issue, must have missed it before. – nurdyguy Dec 19 '17 at 23:04
  • This issue is still present in core 2.2. Thanks for the filter solution, it helped me out. – HighCs Mar 13 '19 at 01:47
  • This issue is present in .net core 3.1 as well.. seems like they have taken this workaround for the real solution – Rahul Ranjan Jun 22 '21 at 16:18