在所有视图上访问Viewbag属性

时间:2014-12-05 03:59:37

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

如何在所有视图中访问某些ViewBag属性?我希望在任何地方都能访问当前用户名等信息,但无需在项目的每个ActionResult方法中专门定义属性

4 个答案:

答案 0 :(得分:17)

你可以通过多种方式实现自己想要的目标,每种方式都有其优点和缺点。

<强> 1。使用基类

public class BaseController : Controller
{
    protected override ViewResult View(IView view, object model)
    {
        this.ViewBag.MyProperty = "value";
        return base.View(view, model);
    }
}

PROS :实施起来非常简单,几行代码,高度可重用,可以随意选择(参见下面的评论)。

CONS :被迫从基类派生所有控制器可能会产生一些影响,特别是如果你已经有很多控制器和/或你需要从其他基础派生它们类。

<强> 2。使用模块

public class ViewBagPropertyModule: Module
{
    protected override void AttachToComponentRegistration(IComponentRegistry cr,
                                                  IComponentRegistration reg)
    {
        Type limitType = reg.Activator.LimitType;
        if (typeof(Controller).IsAssignableFrom(limitType))
        {
            registration.Activated += (s, e) =>
            {
                dynamic viewBag = ((Controller)e.Instance).ViewBag;
                viewBag.MyProperty= "value";
            };
        }
    }
}

PROS :我不知道。

缺点:没有我知道(除了有点违反直觉)。

第3。使用 RegisterController Hook

builder.RegisterControllers(asm)
    .OnActivated(e => {
        dynamic viewBag = ((Controller)e.Instance).ViewBag;
        viewBag.MyProperty = "value";
    });

PROS :快速,安全,可重复使用:适用于任何IoC设计模式。

缺点:并不总是适合小型项目和/或简单网站:如果您不使用IoC,则通常根本不使用RegisterController。

<强> 4。使用ActionFilter属性

public class MyPropertyActionFilter : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        filterContext.Controller.ViewBag.MyProperty = "value";
    }
}

然后在你的Global.asax.cs文件中:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    GlobalFilters.Filters.Add(new MyPropertyActionFilter(), 0);
}

PROS :在所提到的方法中轻松采用不那么突兀的方法。

缺点:没有我知道。

我还在我的博客上写了this article来解释上述所有方法。

答案 1 :(得分:16)

完成您的要求的最佳和直接的方法是创建一个自定义基本控制器并从该基本控制器继承您的控制器。

public class MyBaseController : Controller
{
    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        ViewBag.someThing = "someThing"; //Add whatever
        base.OnActionExecuting(filterContext);
    }
}

现在,不要继承Controller类,而是在Controller中继承MyBaseController,如下所示: -

public class MyOtherController : MyBaseController 
{
    public ActionResult MyOtherAction()
    {
       //Your Stuff
       return View();
    }
    //Other ActionResults
}

答案 2 :(得分:6)

一种方法:创建自定义属性,然后可以在FilterConfig中全局应用它。然后,您无需在控制器中执行任何操作。

public class MyCustomViewActionFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        dynamic ViewBag = filterContext.Controller.ViewBag;

        ViewBag.Id = "123";
        ViewBag.Name = "Bob";
    }
}

App_Start/FilterConfig.cs

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new MyCustomViewActionFilter());
    }

另一种方法,如果你需要的只是用户信息。您可以将以下内容添加到视图的顶部:

@using Microsoft.AspNet.Identity

然后使用以下语法访问您的用户名:

@User.Identity.GetUserName()

您还可以覆盖IPrincipal实现并提供自己的属性和方法,以添加渲染所需的更多信息。

UPDATE :在Asp.Net vNext中查看MVC 6,这实际上已经融入了框架。 http://www.asp.net/vnext/overview/aspnet-vnext/vc#inj

答案 3 :(得分:0)

我目前的解决方案:

创建一个包含所有必需属性的基本控制器(非常有用且可取)。

public abstract class BaseController : Controller {
    public string MyProperty { get; set; }
}

从基本控制器继承所有控制器。

public class MyController : BaseController {
    //you can read your property here
}

在你的观点中,在“@model”句子后面添加这一行:

@{ BaseController ctr = ViewContext.Controller as BaseController; }

现在,您可以在视图中使用该属性,而无需填充ViewBag,无需检查和转换ViewBag值等。

在视图中,您可以使用简单的内联表达式:

@(ctr.MyProperty)

或做一些神奇的逻辑...

@{
    if(ctr.MyProperty == "whatelse") {
        //do ...
    }
}

轻松,快捷,舒适。