如何为所有视图设置ViewBag属性而不使用控制器的基类?

在过去,我通过让所有的控制器都从一个通用的基础控制器inheritance,将公共属性(如当前用户)以全局方式粘贴到ViewData / ViewBag上。

这使我可以在基本控制器上使用IoC,而不仅仅是将这些数据分享到全局共享中。

我想知道是否有一种替代方式插入这种types的代码到MVCpipe道?

未经我的尝试,但您可能会注册您的意见 ,然后在激活过程中设置视图数据。

由于视图是在运行中注册的,所以注册语法不能帮助您连接到Activated事件,所以您需要在Module进行设置:

 class SetViewBagItemsModule : Module { protected override void AttachToComponentRegistration( IComponentRegistration registration, IComponentRegistry registry) { if (typeof(WebViewPage).IsAssignableFrom(registration.Activator.LimitType)) { registration.Activated += (s, e) => { ((WebViewPage)e.Instance).ViewBag.Global = "global"; }; } } } 

这可能是我唯一的那种“唯一工具一锤子”式的build议; 可能有简单的MVC启用的方法来获取它。

编辑:备用,less代码方法 – 只需连接到控制器

 public class SetViewBagItemsModule: 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.Config = e.Context.Resolve<Config>(); viewBag.Identity = e.Context.Resolve<IIdentity>(); }; } } } 

编辑2:从控制器注册码直接工作的另一种方法:

 builder.RegisterControllers(asm) .OnActivated(e => { dynamic viewBag = ((Controller)e.Instance).ViewBag; viewBag.Config = e.Context.Resolve<Config>(); viewBag.Identity = e.Context.Resolve<IIdentity>(); }); 

最好的方法是使用ActionFilterAttribute并在您的全局注册您的自定义类。 asax(Application_Start)

 public class UserProfilePictureActionFilter : ActionFilterAttribute { public override void OnResultExecuting(ResultExecutingContext filterContext) { filterContext.Controller.ViewBag.IsAuthenticated = MembershipService.IsAuthenticated; filterContext.Controller.ViewBag.IsAdmin = MembershipService.IsAdmin; var userProfile = MembershipService.GetCurrentUserProfile(); if (userProfile != null) { filterContext.Controller.ViewBag.Avatar = userProfile.Picture; } } } 

注册您的自定义类在您的全球。 asax(Application_Start)

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

那么你可以在所有的意见中使用它

 @ViewBag.IsAdmin @ViewBag.IsAuthenticated @ViewBag.Avatar 

还有另一种方法

在HtmlHelper上创build一个扩展方法

 [Extension()] public string MyTest(System.Web.Mvc.HtmlHelper htmlHelper) { return "This is a test"; } 

那么你可以在所有的意见中使用它

 @Html.MyTest() 

由于ViewBag的属性,根据定义,绑定到视图的演示文稿和任何轻视图逻辑,可能是必要的, 我会创build一个基本的WebViewPage和页面初始化设置属性。 这与基本控制器的概念非常类似,用于重复逻辑和通用function,但对于您的观点:

  public abstract class ApplicationViewPage<T> : WebViewPage<T> { protected override void InitializePage() { SetViewBagDefaultProperties(); base.InitializePage(); } private void SetViewBagDefaultProperties() { ViewBag.GlobalProperty = "MyValue"; } } 

然后在\Views\Web.config中设置pageBaseType属性:

 <system.web.webPages.razor> <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <pages pageBaseType="MyNamespace.ApplicationViewPage"> <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing" /> </namespaces> </pages> </system.web.webPages.razor> 

布兰登的职位是对的钱。 事实上,我会进一步说,你应该只是添加你的公共对象作为基础WebViewPage的 属性 ,所以你不必从每个视图的ViewBag中投射项目。 我这样做我的CurrentUser设置。

你可以使用一个自定义的ActionResult:

 public class GlobalView : ActionResult { public override void ExecuteResult(ControllerContext context) { context.Controller.ViewData["Global"] = "global"; } } 

甚至是一个ActionFilter:

 public class GlobalView : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.Result = new ViewResult() {ViewData = new ViewDataDictionary()}; base.OnActionExecuting(filterContext); } } 

有一个MVC 2项目开放,但这两种技术仍然适用于微小的变化。

如果你想在你的视图中的属性编译时间检查和智能感知,然后ViewBag是不是要走的路。

考虑一个BaseViewModel类,并让你的其他视图模型inheritance这个类,例如:

基本视图模型

 public class BaseViewModel { public bool IsAdmin { get; set; } public BaseViewModel(IUserService userService) { IsAdmin = userService.IsAdmin; } } 

查看特定的ViewModel

 public class WidgetViewModel : BaseViewModel { public string WidgetName { get; set;} } 

现在查看代码可以直接在视图中访问属性

 <p>Is Admin: @Model.IsAdmin</p> 

您不必混淆操作或更改模型,只需使用基本控制器并从layout viewcontext转换现有的控制器即可。

用所需的公共数据(标题/页面/位置等)和动作初始化创build一个基础控制器…

 public abstract class _BaseController:Controller { public Int32 MyCommonValue { get; private set; } protected override void OnActionExecuting(ActionExecutingContext filterContext) { MyCommonValue = 12345; base.OnActionExecuting(filterContext); } } 

确保每个控制器都使用基本控制器…

 public class UserController:_BaseController {... 

_Layout.cshml页面的视图上下文中_Layout.cshml现有的基础控制器…

 @{ var myController = (_BaseController)ViewContext.Controller; } 

现在你可以从布局页面引用基本控制器中的值。

 @myController.MyCommonValue 

我发现以下方法是最有效的,并在需要时利用_ViewStart.chtml文件和条件语句提供出色的控制:

_ ViewStart

 @{ Layout = "~/Views/Shared/_Layout.cshtml"; var CurrentView = ViewContext.Controller.ValueProvider.GetValue("controller").RawValue.ToString(); if (CurrentView == "ViewA" || CurrentView == "ViewB" || CurrentView == "ViewC") { PageData["Profile"] = db.GetUserAccessProfile(); } } 

ViewA

 @{ var UserProfile= PageData["Profile"] as List<string>; } 

注意

PageData将在视图中完美工作; 但是,在部分视图的情况下,它将需要从视图传递给子部分。