ASP.NET MVC2 вызывать метод службы с главной страницы? - PullRequest
2 голосов
/ 15 мая 2011

Как в моем приложении MVC2, использующем шаблон Service - Repository, как я могу вызвать метод сервиса с главной страницы?

+--------------------------------------+
| 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>

Но прежде чем я смогу это сделать, мне нужно знать, как на самом деле вызвать метод обслуживания у мастера.

EDIT:

Я адаптировал ответ Дарина и получил:

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 ]

2 голосов
/ 15 мая 2011

Вы можете написать собственный 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 мастер.

1 голос
/ 15 мая 2011

Все, что требует логики, не должно быть в представлениях, включая, конечно, их помощников.

Я бы предложил для этого добавить новое действие контроллера, добавить свою логику в действие и вернуть имя пользователя напрямую.из контроллера или, если вы хотите, чтобы отображались другие элементы, такие как элементы управления входом, все, что вы можете использовать для представления.

Итак, создайте класс LoginWelcomeMessage со свойствами Username и IsLoggedIn, например.В действии установите те, которые основаны на любых проверках, которые вы хотите, и отправьте их в представление, которое показывает / скрывает на их основе.

На главной странице вы выполняете @Html.RenderAction(), чтобы выполнить действие, которое приносит имя пользователяи т. д.

Та же идея может быть реализована для всего меню.Это зависит от вас, иметь ли весь заголовок в одном Action / View или два разных.Если у вас такое же представление, то модель может иметь дополнительные свойства, такие как CanViewSalesMenuItems, CanViewAdminMenuItems и т. Д., Которые устанавливаются из вашего метода действия и используются из его представления для отображения / скрытия элементов.

Прелесть в том, что главной странице все равно, она просто передает все это действию контроллера и его просмотру, используя RenderAction()

...