在我使用Service-Repository模式的MVC2应用程序中,如何从母版页调用服务方法?
+--------------------------------------+
| Logo Welcome xyz|
+--------------------------------------+
| Home | Sales | Import | Admin (menu) |
+--------------------------------------+
在我的菜单中,我现在有一些页面限制了用户角色的访问权限。我有一个现有的服务方法,可以检查当前用户是否可以查看某个页面:
IPageAccessService.CanAccess(int pageId, int roleId);
在控制器方法上,我可以调用它来检查用户是否可以看到该页面:
public ActionResult Update(int id?)
{
if (!_pageAccessService.CanAccess(pageId, roleId))
{
return RedirectToAction("Index", "Home");
}
}
但我不知道如何从我的Site.Master调用此方法,以便在创建菜单时,如果用户没有访问权限(菜单是一个简单的无序列表),则不显示菜单项:
<li><a href="<%=Url.Content("~/Admin") %>">Admin</a>
<ul>
<li><a href="<%=Url.Content("~/Admin/Roles") %>">User Roles</a></li>
<li><a href="<%=Url.Content("~/Admin/AdminReports") %>">Admin Reports</a></li>
</ul>
</li>
我猜它需要看起来像这样(必须在添加到列表之前检查每一页):
if (_pageAccessService.CanAccess(pageId, roleId)) <li><a href="<%=Url.Content("~/Admin") %>">Admin</a>
<ul>
if (_pageAccessService.CanAccess(pageId, roleId)) <li><a href="<%=Url.Content("~/Admin/Roles") %>">User Roles</a></li>
if (_pageAccessService.CanAccess(pageId, roleId)) <li><a href="<%=Url.Content("~/Admin/AdminReports") %>">Admin Reports</a></li>
</ul>
</li>
但在我能做到这一点之前,我需要知道如何从主服务器中实际调用服务方法。
编辑:
我已经调整了达林的答案并且有了这个:
public static class LinkExtensions
{
private static readonly IPageAccessRepository _repo = new PageAccessRepository();
private static readonly IPageAccessService _pageAccess = new PageAccessService(_repo);
public static MvcHtmlString MenuItem(
this HtmlHelper htmlHelper, string linkText,
string url, string pageName
)
{
if (!_pageAccess.CanAccess(pageName))
{
return MvcHtmlString.Empty;
}
// The user can access the page => show the menu
var a = new TagBuilder("a");
a.Attributes["href"] = url;
a.SetInnerText(linkText);
return MvcHtmlString.Create(string.Format("<li>{0}</li>",a));
}
问题是我仍然需要调用该服务,所以我需要能够实例化它。因为它是一个静态类,我的IoC容器在这里无济于事。所以我仍然需要手动创建服务和存储库。而且它仍然存在与我原来丑陋的解决方法相同的问题 - 在视图中手动创建存储库。
答案 0 :(得分:2)
您可以编写自定义HTML帮助器来呈现此菜单的不同项目。在基于用户角色的帮助程序内部,您将决定是否生成给定项目。例如,行中的某些内容:
public static class LinkExtensions
{
public static MvcHtmlString MenuItem(
this HtmlHelper htmlHelper,
string linkText,
string url,
string requiredRole
)
{
var a = new TagBuilder("a");
a.Attributes["href"] = url;
a.SetInnerText(linkText);
if (string.IsNullOrEmpty(requiredRole))
{
// No role required => show the menu item
return MvcHtmlString.Create(a.ToString());
}
var user = htmlHelper.ViewContext.HttpContext.User;
if (!user.IsInRole(requiredRole))
{
// A role is required but no user authenticated or user is not in role
// => show empty
return MvcHtmlString.Empty;
}
// The user is in role => show the menu
return MvcHtmlString.Create(a.ToString());
}
}
并在视图中:
<li>
<%= Html.MenuItem("Admin", Url.Content("~/Admin"), "admin") %>
<ul>
<li>
<%= Html.MenuItem("User Roles", Url.Content("~/Admin/Roles"), "userroles") %>
</li>
<li>
<%= Html.MenuItem("Admin Reports", Url.Content("~/Admin/AdminReports"), "admin") %>
</li>
</ul>
</li>
另一种可能性是使用子操作和主文件中的Html.Action helper。
答案 1 :(得分:1)
任何需要逻辑的东西都不应该在Views中,包括他们的助手当然。
我建议您为此添加一个新的Controller Action,将您的逻辑添加到操作中,并直接从控制器返回用户名,或者如果您想显示更多内容,例如登录控件,您可以使用视图。< / p>
因此,例如,使用LoginWelcomeMessage
和Username
属性创建IsLoggedIn
类。在动作中根据您想要的任何检查设置,并将它们发送到基于它们显示/隐藏的视图。
在您的母版页中,您执行@Html.RenderAction()
以执行带来用户名的操作,依此类推。
可以对整个菜单做同样的想法。由您决定是将整个标题放在一个动作/视图中还是有两个不同的标题。如果您具有相同的视图,那么模型可以具有额外的属性,如CanViewSalesMenuItems
,CanViewAdminMenuItems
等,这些属性是根据您的操作方法设置的,并从其视图中用于显示/隐藏项目。
美丽是主页不关心,它只是使用RenderAction()