In my MVC2 app that uses the Service – Repository pattern, how can I call a service method from the master page?
+--------------------------------------+
| Logo Welcome xyz|
+--------------------------------------+
| Home | Sales | Import | Admin (menu) |
+--------------------------------------+
In my menu I now have some pages that have restricted access by user role. I have an existing service method that can check if the current user can view a certain page or not:
IPageAccessService.CanAccess(int pageId, int roleId);
On the controller methods I can call this to check if the user can see the page or not:
public ActionResult Update(int id?)
{
if (!_pageAccessService.CanAccess(pageId, roleId))
{
return RedirectToAction("Index", "Home");
}
}
But I don’t know how to call this method from my Site.Master so that when it creates the menu it does not show the menu item if the user does not have access (the menu is a simple unordered list):
<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>
I’m guessing that it would need look something like this (have to check each page before adding to the list):
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>
But before I can do that I need to know how to actually call a service method from the master.
EDIT:
I’ve adapted Darin’s answer and have this:
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));
}
The problem is that I still need to call the service, so I need to be able to instantiate it. Because its a static class, my IoC container won’t help here. So I still have to manually do create the service and repository. And it’s still got the same problem as my original ugly workaround – manually creating a repository in a view.
You could write a custom HTML helper rendering the different items of this menu. Inside the helper based on the user roles you will decide whether to generate or not the given item. For example something among the lines:
and inside the view:
Another possibility is to use child actions and the Html.Action helper inside the master.