asp.net-mvc 如何在不使用控制器基类的情况下为所有视图设置 ViewBag 属性?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5453327/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to set ViewBag properties for all Views without using a base class for Controllers?
提问by Scott Weinstein
In the past I've stuck common properties, such as the current user, onto ViewData/ViewBag in a global fashion by having all Controllers inherit from a common base controller.
过去,我通过让所有控制器继承自一个公共基本控制器,以全局方式将公共属性(例如当前用户)粘贴到 ViewData/ViewBag 上。
This allowed my to use IoC on the base controller and not just reach out into global shared for such data.
这允许我在基本控制器上使用 IoC,而不仅仅是针对此类数据访问全局共享。
I'm wondering if there is an alternate way of inserting this kind of code into the MVC pipeline?
我想知道是否有将这种代码插入 MVC 管道的替代方法?
采纳答案by Nicholas Blumhardt
Un-tried by me, but you might look at registering your viewsand then setting the view data during the activation process.
我没有尝试过,但您可能会考虑注册您的视图,然后在激活过程中设置视图数据。
Because views are registered on-the-fly, the registration syntax doesn't help you with connecting to the Activated
event, so you'd need to set it up in a Module
:
因为视图是即时注册的,注册语法不能帮助您连接到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";
};
}
}
}
This might be one of those "only tool's a hammer"-type suggestions from me; there may be simpler MVC-enabled ways to get at it.
这可能是我提出的“唯一工具是锤子”式的建议之一;可能有更简单的启用 MVC 的方法来实现它。
Edit:Alternate, less code approach - just attach to the Controller
编辑:替代,更少的代码方法 - 只需附加到控制器
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>();
};
}
}
}
Edit 2:Another approach that works directly from the controller registration code:
编辑 2:另一种直接从控制器注册代码工作的方法:
builder.RegisterControllers(asm)
.OnActivated(e => {
dynamic viewBag = ((Controller)e.Instance).ViewBag;
viewBag.Config = e.Context.Resolve<Config>();
viewBag.Identity = e.Context.Resolve<IIdentity>();
});
回答by Mohammad Karimi
The best way is using ActionFilterAttribute and register your custom class in your global. asax (Application_Start)
最好的方法是使用 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;
}
}
}
register your custom class in your global. asax (Application_Start)
在您的全局注册您的自定义类。asax (Application_Start)
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalFilters.Filters.Add(new UserProfilePictureActionFilter(), 0);
}
Then you can use it in all views
然后你可以在所有视图中使用它
@ViewBag.IsAdmin
@ViewBag.IsAuthenticated
@ViewBag.Avatar
Also there is another way
还有另一种方式
Creating an extension method on HtmlHelper
在 HtmlHelper 上创建扩展方法
[Extension()]
public string MyTest(System.Web.Mvc.HtmlHelper htmlHelper)
{
return "This is a test";
}
Then you can use it in all views
然后你可以在所有视图中使用它
@Html.MyTest()
回答by Brandon Linton
Since ViewBag properties are, by definition, tied to the view presentation and any light view logic that may be necessary, I'd create a base WebViewPageand set the properties on page initialization. It's very similar to the concept of a base controller for repeated logic and common functionality, but for your views:
由于 ViewBag 属性根据定义与视图演示和任何可能需要的轻视图逻辑相关联,因此我将创建一个基本的 WebViewPage并在页面初始化时设置属性。它与用于重复逻辑和通用功能的基本控制器的概念非常相似,但对于您的视图:
public abstract class ApplicationViewPage<T> : WebViewPage<T>
{
protected override void InitializePage()
{
SetViewBagDefaultProperties();
base.InitializePage();
}
private void SetViewBagDefaultProperties()
{
ViewBag.GlobalProperty = "MyValue";
}
}
And then in \Views\Web.config
, set the pageBaseType
property:
然后在 中\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>
回答by Michael Gagne
Brandon's post is right on the money. As a matter of fact, I would take this a step further and say that you should just add your common objects as propertiesof the base WebViewPageso you don't have to cast items from the ViewBag in every single View. I do my CurrentUser setup this way.
布兰登的帖子是关于金钱的。事实上,我会更进一步,并说您应该将公共对象添加为基本 WebViewPage 的属性,这样您就不必在每个视图中从 ViewBag 投射项目。我以这种方式进行 CurrentUser 设置。
回答by John Farrell
You could use a custom ActionResult:
您可以使用自定义 ActionResult:
public class GlobalView : ActionResult
{
public override void ExecuteResult(ControllerContext context)
{
context.Controller.ViewData["Global"] = "global";
}
}
Or even a ActionFilter:
甚至是一个 ActionFilter:
public class GlobalView : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Result = new ViewResult() {ViewData = new ViewDataDictionary()};
base.OnActionExecuting(filterContext);
}
}
Had an MVC 2 project open but both techniques still apply with minor changes.
有一个 MVC 2 项目打开,但两种技术仍然适用,只需稍作更改。
回答by Carter Medlin
You don't have to mess with actions or change the model, just use a base controller and cast the existing controller from the layout viewcontext.
您不必弄乱操作或更改模型,只需使用基本控制器并从布局视图上下文中投射现有控制器即可。
Create a base controller with the desired common data (title/page/location etc) and action initialization...
使用所需的公共数据(标题/页面/位置等)和动作初始化创建一个基本控制器...
public abstract class _BaseController:Controller {
public Int32 MyCommonValue { get; private set; }
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
MyCommonValue = 12345;
base.OnActionExecuting(filterContext);
}
}
Make sure every controller uses the base controller...
确保每个控制器都使用基本控制器...
public class UserController:_BaseController {...
Cast the existing base controller from the view context in your _Layout.cshml
page...
从_Layout.cshml
页面中的视图上下文投射现有的基本控制器......
@{
var myController = (_BaseController)ViewContext.Controller;
}
Now you can refer to values in your base controller from your layout page.
现在您可以从布局页面引用基本控制器中的值。
@myController.MyCommonValue
回答by Steven Quick
If you want compile time checking and intellisense for the properties in your views then the ViewBag isn't the way to go.
如果您想对视图中的属性进行编译时检查和智能感知,那么 ViewBag 不是最佳选择。
Consider a BaseViewModel class and have your other view models inherit from this class, eg:
考虑一个 BaseViewModel 类,并让你的其他视图模型从这个类继承,例如:
Base ViewModel
基础视图模型
public class BaseViewModel
{
public bool IsAdmin { get; set; }
public BaseViewModel(IUserService userService)
{
IsAdmin = userService.IsAdmin;
}
}
View specific ViewModel
查看特定的 ViewModel
public class WidgetViewModel : BaseViewModel
{
public string WidgetName { get; set;}
}
Now view code can access the property directly in the view
现在视图代码可以直接在视图中访问属性
<p>Is Admin: @Model.IsAdmin</p>
回答by usefulBee
I have found the following approach to be the most efficient and gives excellent control utilizing the _ViewStart.chtml file and conditional statements when necessary:
我发现以下方法是最有效的,并在必要时利用 _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:
视图A:
@{
var UserProfile= PageData["Profile"] as List<string>;
}
Note:
注意:
PageData will work perfectly in Views; however, in the case of a PartialView, it will need to be passed from the View to the child Partial.
PageData 将在视图中完美运行;但是,在 PartialView 的情况下,它需要从 View 传递给子 Partial。