在ASP.NET MVC Core控制器的构造函数中设置ViewBag属性

时间:2016-10-30 14:59:50

标签: asp.net asp.net-mvc razor asp.net-core asp.net-core-mvc

我的主题有某种痕迹。控制器始终是类别。为了避免重复我自己,我想在控制器的构造函数中为所有这样的操作设置它:

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。

3 个答案:

答案 0 :(得分:15)

关于它有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
{
}

答案 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类即可完成所有工作。