ASP.NET MVC2从母版页调用服务方法?

时间:2011-05-15 01:34:15

标签: c# web-services asp.net-mvc-2 site.master

在我使用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容器在这里无济于事。所以我仍然需要手动创建服务和存储库。而且它仍然存在与我原来丑陋的解决方法相同的问题 - 在视图中手动创建存储库。

2 个答案:

答案 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>

因此,例如,使用LoginWelcomeMessageUsername属性创建IsLoggedIn类。在动作中根据您想要的任何检查设置,并将它们发送到基于它们显示/隐藏的视图。

在您的母版页中,您执行@Html.RenderAction()以执行带来用户名的操作,依此类推。

可以对整个菜单做同样的想法。由您决定是将整个标题放在一个动作/视图中还是有两个不同的标题。如果您具有相同的视图,那么模型可以具有额外的属性,如CanViewSalesMenuItemsCanViewAdminMenuItems等,这些属性是根据您的操作方法设置的,并从其视图中用于显示/隐藏项目。

美丽是主页不关心,它只是使用RenderAction()

将整个事物委托给控制器操作及其视图