Set the ViewBag property in the ASP.NET MVC Core controller constructor

My theme has its own baby. A controller is always a category. To avoid repetition, I want to set it in the controller constructor for all actions like this:

class MyController:Controller{ public MyController() { ViewBag.BreadcrumbCategory = "MyCategory"; } } 

When I access ViewBag.BreadcrumbCategory in the layout view, its value is null. In action, it works:

 class MyController:Controller{ public IActionResult DoSomething() { ViewBag.BreadcrumbCategory = "MyCategory"; } } 

I am wondering that setting the ViewBag property is not possible in the constructor? It would be very unpleasant and there would be no good practice for a function to call every action that does this work. In another question using the constructor, the answer was accepted, but as I said, this does not work, at least for ASP.NET Core.

+6
source share
2 answers

There is a GitHub problem about this, and he stated that it is by design. The answer you are linking up is ASP.NET MVC3, the old old ASP.NET stack.

ASP.NET Core is written from scratch and uses a variety of concepts designed both for portability (on multiple platforms) and for performance and modern practices such as built-in support for für Dependency Injection.

The latter does not allow you to set the ViewBag in the constructor, because some properties of the Constructor base class must be entered through the Injection Property, as you may have noticed that you do not need to pass these dependencies to your derived controllers.

This means that when the Controller constructor is called, the properties for HttpContext , ControllerContext , etc. not installed. They are installed only after , called by the constructor, and there is a valid instance / reference to this object.

And as stated in the GitHub issues, it will not be fixed because it is by design.

As you can see here , the ViewBag is dependent on the ViewData and the ViewData populated after the controller is initialized. If you call ViewBag.Something = "something" , then you will create a new instance of the DynamicViewData class, which will be replaced with the one after the constructor initialization.

As @SLaks pointed out, you can use the action filter that you configure for each controller.

The following example assumes that you always derive your controllers from the base class Controller .

 public class BreadCrumbAttribute : IActionFilter { private readonly string _name; public BreadCrumbAttribute(string name) { _name = name; } public void OnActionExecuting(ActionExecutingContext context) { base.OnActionExecuting(context); var controller = context.Controller as Controller; if (controller != null) { controller.ViewBag.BreadcrumbCategory = _name; } } } 

Now you can decorate your controller with it.

 [BreadCrumb("MyCategory")] class MyController:Controller { } 
+9
source

I have the same problem and solves it to override the controller's OnActionExecuted method:

  public override void OnActionExecuted(ActionExecutedContext context) { base.OnActionExecuted(context); ViewBag.Module = "Production"; } 
+1
source

Source: https://habr.com/ru/post/1011860/


All Articles