Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Unable to set ViewBag or ViewData entries from Controller constructors #1422

Closed
dougbu opened this issue Oct 21, 2014 · 5 comments
Closed

Unable to set ViewBag or ViewData entries from Controller constructors #1422

dougbu opened this issue Oct 21, 2014 · 5 comments
Labels

Comments

@dougbu
Copy link
Member

dougbu commented Oct 21, 2014

The following works in MVC 5.2 but throws an InvalidOperationException in vNext. This prevents common initialization scenarios unless the user is aware of OnActionExecuting() or OnActionExecutionAsync() (which are less discoverable than MVC 5.2's Initialize() method). ViewData["Items"] doesn't help because ViewData is null.

public class HomeController : Controller
{
  private static readonly IEnumerable<SelectListItem> _items =
    new SelectList(Enumerable.Range(7, 13));

  public HomeController()
  {
    ViewBag.Items = _items;
  }
  ...
}

Details:
The root cause is DefaultControllerActivator creates the controller's ViewDataDictionary instance. So ViewData is null until Controller instances are activated. Worse if ViewBag is used while ViewData is still null, the result is an InvalidOperationException thrown from the DynamicViewData.ViewData getter.

By contrast, few properties in the MVC 5.2 Controller class even return null (let alone throw) if invoked from the constructor. (Exceptions include ControllerContext, Url, and anything ControllerContext-derived e.g. HttpContext and User. All of those simply return null prior to the Initialize() call.)

Probably need to revisit the Controller activation model. At least should look at the properties lazy-initialized in MVC 5.2 and decide if they should be handled similarly in vNext.

@danroth27
Copy link
Member

If we get significant user feedback on this issue we can consider adding a more useful error message, but this behavior is intentional now that we have activated controllers.

@DMW007
Copy link

DMW007 commented Oct 29, 2016

In ASP.NET Core 1.0 I tried to set a page-category title using ViewBag in the constructor of my controller:

class MyController : Controller {
    public MyController() {
        ViewBag.PageCategory = "Test";
    }
}

I use ViewBag.PageCategory in my layout-razor view. When I set it in a single action it works, but not in the constructor. It's not working without any exception or error message.

@rynowak
Copy link
Member

rynowak commented Oct 31, 2016

This behavior is intentional do not do work in your controller's constructor that touches anything stateful or related to the current request. If you want to run some code before any action is invoked, override the OnActionExecuting method defined on Controller.

@DMW007
Copy link

DMW007 commented Nov 1, 2016

@rynowak Thanks, that worked! As an alternative, its also possible to create a DataAnnotation-Attribute. For example, by inheriting from ResultFilterAttribute. This also allow to override the OnActionExecuting method.

@rynowak
Copy link
Member

rynowak commented Nov 1, 2016

@DMWOO7 - yes, that would work as well, but it doesn't have anything to do with System.ComponentModel.DataAnnotations.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants