我的主题有某种痕迹。控制器始终是类别。为了避免重复我自己,我想在控制器的构造函数中为所有这样的操作设置它:
class MyController:Controller{
public MyController() {
ViewBag.BreadcrumbCategory = "MyCategory";
}
}
当我在布局视图中访问ViewBag.BreadcrumbCategory
时,它为null。在一个行动中它起作用:
class MyController:Controller{
public IActionResult DoSomething() {
ViewBag.BreadcrumbCategory = "MyCategory";
}
}
我想知道在构造函数中设置ViewBag属性是不可能的?在执行此工作的每个操作上调用函数将是令人烦恼且没有好的做法。在another question使用构造函数是一个被接受的answear,但正如我所说,这不起作用,至少对于ASP.NET Core。
答案 0 :(得分:15)
关于它有GitHub issue,并且声明这是设计的。您链接的答案是关于ASP.NET MVC3,旧的旧版ASP.NET堆栈。
ASP.NET Core是从头开始编写的,它使用不同的概念,专为可移植性(多个平台)以及性能和现代实践而设计,例如内置支持依赖注入。
最后一个使得无法在构造函数中设置ViewBag
,因为Constructor
基类的某些属性必须通过Property Injection注入,因为您可能已经注意到您不必在派生控制器中传递这些依赖项。
这意味着,当调用Controller
的构造函数时,不会设置HttpContext
,ControllerContext
等属性。只有在>> >>之后才设置它们,并且对该对象有一个有效的实例/引用。
正如GitHub问题所指出的那样,它不会被修复,因为这是设计上的。
正如您所看到的here,ViewBag依赖于ViewData
,并且在初始化控制器后填充ViewData
。如果你调用ViewBag.Something = "something"
,那么你将创建一个DynamicViewData
类的新实例,它将被构造函数初始化后的实例替换。
正如@SLaks指出的那样,您可以使用为每个控制器配置的操作过滤器。
以下示例假设您始终从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;
}
}
}
现在你应该能够用它来装饰你的控制器。
[BreadCrumb("MyCategory")]
class MyController:Controller
{
}
答案 1 :(得分:3)
我有同样的问题并解决它覆盖控制器的OnActionExecuted
方法:
public override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
ViewBag.Module = "Production";
}
答案 2 :(得分:1)
对于.NET Core 3.x,这是一种更好的方法,请使用ResultFilterAttribute:
创建自己的自定义过滤器属性,该属性将从ResultFilterAttribute继承,如下所示:
public class PopulateViewBagAttribute : ResultFilterAttribute
{
public PopulateViewBagAttribute()
{
}
public override void OnResultExecuting(ResultExecutingContext context)
{
// context.HttpContext.Response.Headers.Add(_name, new string[] { _value });
(context.Controller as MyController).SetViewBagItems();
base.OnResultExecuting(context);
}
}
您需要实现SetViewBagItems方法来填充您的ViewBag
公共无效SetViewBagItems() { ViewBag.Orders =订单; }
然后使用新属性装饰Controller类:
[PopulateViewBag]
public class ShippingManifestController : Controller
仅此而已!如果要从构造函数中各处填充ViewBag,则可以考虑使用抽象方法SetViewBagItems创建控制器基类。然后,您只需要一个ResultFilterAttribute类即可完成所有工作。