Answers:
我未尝试过,但是您可能会考虑注册视图,然后在激活过程中设置视图数据。
由于视图是动态注册的,因此注册语法无法帮助您连接到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";
};
}
}
}
这可能是我提出的“唯一的工具”。可能会有更简单的启用MVC的方法来实现。
编辑:替代方法,更少的代码方法-只需附加到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>();
};
}
}
}
编辑2:直接从控制器注册代码直接工作的另一种方法:
builder.RegisterControllers(asm)
.OnActivated(e => {
dynamic viewBag = ((Controller)e.Instance).ViewBag;
viewBag.Config = e.Context.Resolve<Config>();
viewBag.Identity = e.Context.Resolve<IIdentity>();
});
Resolve
部分e.Context.Resolve
?我应该提到我习惯Ninject ...
最好的方法是使用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上创建扩展方法
[Extension()]
public string MyTest(System.Web.Mvc.HtmlHelper htmlHelper)
{
return "This is a test";
}
然后您可以在所有视图中使用它
@Html.MyTest()
MembershipService
?
根据定义,由于ViewBag属性与视图表示以及可能需要的任何浅视图逻辑相关联,因此我将创建一个基本的WebViewPage并在页面初始化时设置属性。它与用于重复逻辑和通用功能的基本控制器的概念非常相似,但对于您的观点是:
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>
ViewBag.Title
属性来处理的,然后共享布局中唯一的内容是<title>@ViewBag.Title</title>
。由于每个视图都是不同的,因此它实际上不适用于基本应用程序视图页面,而基本视图页面将用于所有视图之间真正通用的数据。
布兰登的职位是对的钱。实际上,我将更进一步,并说您应该只将常见对象添加为基本WebViewPage的属性,这样就不必在每个View中都从ViewBag投射项目。我以这种方式设置CurrentUser。
'ASP._Page_Views_Shared__Layout_cshtml' does not contain a definition for 'MyProp' and no extension method 'MyProp' accepting a first argument of type 'ASP._Page_Views_Shared__Layout_cshtml' could be found (are you missing a using directive or an assembly reference?)
您可以使用自定义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项目,但是这两种技术仍然适用,但都做了些微更改。
您不必弄乱动作或更改模型,只需使用基本控制器,然后从布局viewcontext投射现有的控制器即可。
使用所需的公共数据(标题/页面/位置等)创建基本控制器并进行动作初始化...
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
页面的视图上下文中投射现有的基本控制器。
@{
var myController = (_BaseController)ViewContext.Controller;
}
现在,您可以从布局页面引用基本控制器中的值。
@myController.MyCommonValue
如果要对视图中的属性进行编译时检查和智能感知,则ViewBag并非可行之路。
考虑一个BaseViewModel类,并让您的其他视图模型从该类继承,例如:
基本ViewModel
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>
我发现以下方法是最有效的,并在必要时利用_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将在Views中完美运行;但是,对于PartialView,则需要将其从View传递给子Partial。