在 ASP.NET MVC Core 控制器的构造函数中设置 ViewBag 属性
Posted
技术标签:
【中文标题】在 ASP.NET MVC Core 控制器的构造函数中设置 ViewBag 属性【英文标题】:Set ViewBag property in the constructor of a ASP.NET MVC Core controller 【发布时间】:2016-10-30 14:59:49 【问题描述】:我的主题有某种面包屑。控制器始终是类别。为了避免重复自己,我想在控制器的构造函数中为所有这样的操作设置它:
class MyController:Controller
public MyController()
ViewBag.BreadcrumbCategory = "MyCategory";
当我在布局视图中访问ViewBag.BreadcrumbCategory
时,它为空。在一个动作中它起作用:
class MyController:Controller
public IActionResult DoSomething()
ViewBag.BreadcrumbCategory = "MyCategory";
我想知道在构造函数中设置 ViewBag 属性是不可能的?在执行此工作的每个操作上调用一个函数会很烦人,也不是一个好的做法。在another question 中,使用构造函数是一个公认的答案,但正如我所说,这不起作用,至少对于 ASP.NET Core 而言。
【问题讨论】:
您应该使用操作过滤器。 【参考方案1】:有一个关于它的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
【讨论】:
使用最新版本的 dotnetcore,IActionFilter
需要同时实现 OnActionExecuting
和 OnActionExecuted
。这两个都不是异步函数,所以 await 会导致错误状态,并且基础项是类型对象,因此它没有要调用的 OnActionExecuting
函数。
@Grungondola:ASP.NET Core 也有异步操作过滤器:使用IAsyncActionFilter
接口,但上面的代码没有异步操作,所以同步一个可以正常工作。刚刚删除了 await 关键字,不知道它是怎么进来的【参考方案2】:
我有同样的问题并解决它覆盖控制器的OnActionExecuted
方法:
public override void OnActionExecuted(ActionExecutedContext context)
base.OnActionExecuted(context);
ViewBag.Module = "Production";
【讨论】:
此答案适用于 MVC Core【参考方案3】:对于 .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 类即可完成所有工作。
【讨论】:
以上是关于在 ASP.NET MVC Core 控制器的构造函数中设置 ViewBag 属性的主要内容,如果未能解决你的问题,请参考以下文章
如何将我自己的类注入到 ASP.NET MVC Core 的控制器中?
[Asp.Net Core]Autofac整合.NET5 MVC
[Asp.Net Core]Autofac整合.NET5 MVC
ASP.net core MVC Framework 5 Formdata在附加图像时类型不正确
ASP.NET Core Web 应用程序系列- 在ASP.NET Core中使用Autofac替换自带DI进行构造函数和属性的批量依赖注入(MVC当中应用)
ASP.NET Core Web 应用程序系列- 在ASP.NET Core中使用Autofac替换自带DI进行构造函数和属性的批量依赖注入(MVC当中应用)