My theme has some sort of breadcrumb. The controller is always the category. To avoid repeat myself, I want to set it in the constructor of the controller for all actions like this:
class MyController:Controller{
public MyController() {
ViewBag.BreadcrumbCategory = "MyCategory";
}
}
When I access ViewBag.BreadcrumbCategory
in the layout-view, its null. In a Action it works:
class MyController:Controller{
public IActionResult DoSomething() {
ViewBag.BreadcrumbCategory = "MyCategory";
}
}
I'm wondering that setting a ViewBag property is not possible in a constructor? It would be annoying and no good practice to have a function called on every action which do this work. In another question using the constructor was an accepted answear, but as I said this doesn't work, at least for ASP.NET Core.
To pass the strongly typed data from Controller to View using ViewBag, we have to make a model class then populate its properties with some data and then pass that data to ViewBag with the help of a property. And then in the View, we can access the data of model class by using ViewBag with the pre-defined property.
In general, ViewBag is a way to pass data from the controller to the view. It is a type object and is a dynamic property under the controller base class.
The ViewBag object value will be set inside Controller and then the value of the ViewBag object will be accessed in the cshtml file (View) using Razor syntax in ASP.Net MVC Razor.
The ViewBag in ASP.NET MVC is used to transfer temporary data (which is not included in the model) from the controller to the view. Internally, it is a dynamic type property of the ControllerBase class which is the base class of the Controller class.
There is an GitHub issue about it and it's stated that this is by design. The answer you linked is about ASP.NET MVC3, the old legacy ASP.NET stack.
ASP.NET Core is written from scratch and uses different concepts, designed for both portability (multiple platforms) as well as for performance and modern practices like built-in support for Dependency Injection.
The last one makes it impossible to set ViewBag
in the constructor, because certain properties of the Constructor
base class must be injected via Property Injection as you may have noticed that you don't have to pass these dependencies in your derived controllers.
This means, when the Controller
's constructor is called, the properties for HttpContext
, ControllerContext
etc. are not set. They are only set after the constructor is called and there is a valid instance/reference to this object.
And as pointed in the GitHub issues, it won't be fixed because this is by design.
As you can see here, ViewBag has a dependency on ViewData
and ViewData
is populated after the controller is initialized. If you call ViewBag.Something = "something"
, then you it will create a new instance of the DynamicViewData
class, which will be replaced by the one after the constructor gets initialized.
As @SLaks pointed out, you can use an action filter which you configure per controller.
The following example assumes that you always derive your controllers from Controller
base class.
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 should be able to decorate your controller with it.
[BreadCrumb("MyCategory")]
class MyController:Controller
{
}
I have the same issue and solve it overriding the OnActionExecuted
method of the controller:
public override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
ViewBag.Module = "Production";
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With