在 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 的构造函数时,HttpContextControllerContext 等的属性没有设置。它们仅在构造函数被调用并且存在对该对象的有效实例/引用之后设置。

正如 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 需要同时实现 OnActionExecutingOnActionExecuted。这两个都不是异步函数,所以 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当中应用)