我正在构建一个非常大的MVC项目,我的查看数据有些麻烦。我有一个非常复杂的模型结构。我不想要“反对”#39;我的模型有简单的显示数据,但我想要强类型数据,所以我写了几个简单的类:
public class GeneralViewData
{
private static string Id = "GeneralViewData";
public string PageTitle { get; set; }
public bool ShowGuestMenu { get; set; }
public string CurrentUserName { get; set; }
public bool ShowOrganisationAdminMenu { get; set; }
protected GeneralViewData() { }
public static GeneralViewData Retrieve(ViewDataDictionary viewDataDictionary)
{
object viewData = viewDataDictionary[Id];
if (viewData == null) return Initiate(viewDataDictionary);
return (GeneralViewData)viewData;
}
private static GeneralViewData Initiate(ViewDataDictionary viewDataDictionary)
{
GeneralViewData viewData = new GeneralViewData();
viewDataDictionary[Id] = viewData;
return viewData;
}
}
因此,只要您可以访问ViewData,就可以轻松获取模型并通过以下方式访问它:
var generalViewData = GeneralViewData.Retrieve(ViewData);
这适用于大多数网站,但我遇到了MVCSiteMapProvider视图的问题。显然,sitemapprovrov不会传递主ViewData,而是将新的ViewData传递给部分视图。
我需要一种方法让MVCSiteMapProvider将完整的ViewData传递给它的视图,或者通过在其他地方存储GeneralViewData实例来完全解决这个问题。我一直在绞尽脑汁想要解决这个问题,所以我可以做任何事情。
答案 0 :(得分:1)
选项#1
您可以使用SiteMapTitleAttribute,但由于您的节点是菜单的一部分,因此您必须在每个控制器操作方法中执行此操作。
选项#2
要使其在全局工作而不将SiteMapTitleAttribute添加到每个控制器操作,您还可以在Application_PostAuthorizeRequest事件中显式设置标题。
protected void Application_PostAuthorizeRequest(object sender, EventArgs eventArgs)
{
var user = HttpContext.Current.User;
if (user.Identity.IsAuthenticated)
{
var accountNode = MvcSiteMapProvider.SiteMaps.Current.FindSiteMapNodeFromKey("MyAccount");
if (accountNode != null)
{
accountNode.Title = "Hello, " + user.Identity.Name;
}
}
}
这假设您的帐户节点配置了一个显式密钥集,其值为“MyAccount”。
选项#3
更简洁的方法可能是使用custom attribute添加可以检索当前用户名和其他属性的类。
如果在上面的Application_PostAuthorizeRequest事件中设置对象,则可能会将现有对象用于静态属性。
但是,更集成的方法是使用[IDynamicNodeProvider]或ISiteMapNodeProvider来提供自定义对象。请注意,如果您使用此路由,则需要使用具有从当前请求检索数据的属性/方法的对象(而不是存储它们),因为此对象将在SiteMap的所有用户之间共享。
然后,您可以自定义MvcSiteMapProvider显示模板,以便在自定义对象存在时在适当的节点上显示此数据。
选项#4
按照IPrincipal所述实施IIdentity和/或here,更好地将模型与ASP.NET集成,然后将您的个人资料数据添加到自定义IPrincipal和/或IIdentity实施中所以它可以通过HttpContext对象全局使用。
数据全局可用后,您可以直接从您的视图中访问它。然后,您可以自定义SiteMapNodeModel显示模板,以便在适当时显示数据。
@model MvcSiteMapProvider.Web.Html.Models.SiteMapNodeModel
@using System.Web.Mvc.Html
@using MvcSiteMapProvider.Web.Html.Models
@* Fix the title for the MyAccount Node *@
var title = Model.Title;
if (Model.Key == "MyAccount")
{
title = "Hello, " + (User as CustomPrincipal).CurrentUserName;
}
@if (Model.IsCurrentNode && Model.SourceMetadata["HtmlHelper"].ToString() != "MvcSiteMapProvider.Web.Html.MenuHelper") {
<text>@title</text>
} else if (Model.IsClickable) {
if (string.IsNullOrEmpty(Model.Description))
{
<a href="@Model.Url">@title</a>
}
else
{
<a href="@Model.Url" title="@Model.Description">@title</a>
}
} else {
<text>@title</text>
}
此示例假定您已明确将帐户节点的键属性/属性设置为“MyAccount”。
我还建议您不要使用“ShowGuestMenu”和“ShowOrganisationAdminMenu”的布尔值,而是为此创建一个ASP.NET角色,并使用AuthorizeAttribute与Security Trimming一起控制子的可见性菜单。如果您希望用户能够打开和关闭菜单,我建议您按照自己的方式进行操作,在这种情况下,我建议您使用custom visibility provider而不是通过更改显示模板来控制可见性。