Перенаправление на один и тот же ActionResult с разных контроллеров - PullRequest
2 голосов
/ 17 февраля 2010

У меня есть пользовательская сущность, и в разных видах я хочу создать ссылки на домашнюю страницу пользователя. Эта функциональность должна быть доступна на разных контроллерах, чтобы я мог легко перенаправить на домашнюю страницу пользователя. Каждый пользователь на моем сайте имеет свою роль; например, читатель, писатель, редактор, менеджер и администратор. В идеале я хочу попытаться добиться чего-то подобного:

В контроллере, например

public ActionResult SomeThingHere() {
    return View(User.GetHomePage());
//OR 
    return RedirectToROute(User.GetHomePage());
}

в представлении, я также хочу использовать те же функции, например:

<%= Html.ActionLink("Link to home", user.GetHomePage() %>

Возможно ли добиться такого дизайна в MVC? Если так, как я должен идти об этом?

В настоящее время я использую такой метод, но на данный момент он используется только в одном контроллере. Теперь мне нужно использовать тот же код где-нибудь еще, и я пытаюсь выяснить, как я могу это исправить и избежать повторения?

....
private ActionResult GetHomePage(User user){
    if (user.IsInRole(Role.Admin))
        return RedirectToAction("Index", "Home", new { area = "Admin" });

    if (user.IsInRole(Role.Editor))
        // Managers also go to editor home page
        return RedirectToAction("Index", "Home", new {area = "Editor"});

    if (user.IsInRole(Role.Reader))
        // Writer and reader share the same home page
        return RedirectToAction("Index", "Home", new { area = "Reader" });

    return RedirectToAction("Index", "Home");
}
...

Ответы [ 3 ]

1 голос
/ 17 февраля 2010

Как насчет этого:

private string GetArea(User u)
{
   string area = string.empty;
   if (User.IsInRole(Admin)) area = "admin";
   else if (...)


   return area;
}
0 голосов
/ 23 февраля 2010

Ну, я наконец-то придумал дизайн, который, кажется, работает. Я написал расширение контроллера, с помощью метода GetHomePage. Это расширение также может быть использовано в ваших представлениях. Вот как я это сделал:

public static class UserHelperExtension    {
    public static string GetHomePage(this ControllerBase controller, User user) {
        return = "http://" + controller.ControllerContext
                            .HttpContext.Request
                            .ServerVariables["HTTP_HOST"] + "/"
                           + GetHomePage(user);
    }

    //need this for views
    public static string GetHomePage(string httphost, User user) {
        return  = "http://" + httphost + "/" + GetHomePage(user});
    }

    private static string GetHomePage(User user) {
        if (user.IsInRole(Role.Admin))
            return "/Admin/Home/Index";
        if (user.IsInRole(Role.Editor))
            return "/Editor/Home/Index";
        if (user.IsInRole(Role.Reader))
            return "/Reader/Home/Index";
        return "/Home/Index";
    }
}

Метод действия в контроллере выглядит следующим образом:

    using Extensions;
...
public ActionResult SomethingHere() {
    return Redirect(this.GetHomePage(user));
}
...

В представлении у меня есть это:

...
<%@ Import Namespace="Extensions"%>
<%=UserHelperExtension.GetHomePage(Request.ServerVariables["HTTP_HOST"], user)%>
...

Преимущество состоит в том, что я могу легко использовать этот метод "GetHomePage" в различных контроллерах, или просматривает мое приложение, и логика в одном месте. Недостатком является то, что Я бы предпочел иметь более безопасный тип. Например, в моих оригинальных тестах у меня был доступ к коллекции RouteValues:

public void User_should_redirect_to_role_home(Role role,
    string area, string controller, string action) {
...
var result = (RedirectToRouteResult)userController.SomeThingHere();
    Assert.That(result.RouteValues["area"], 
        Is.EqualTo(area).IgnoreCase);
    Assert.That(result.RouteValues["controller"], 
        Is.EqualTo(controller).IgnoreCase);
    Assert.That(result.RouteValues["action"], 
        Is.EqualTo(action).IgnoreCase);
...

}

Но теперь, когда я использую строку, так что она небезопасна, я проверяю RedirectResult.Url.

...
var result = (RedirectResult) userController.SomethingHere();
Assert.That(result.Url.EndsWith("/" + area + "/" + controller + "/" + action), 
    Is.True);
...
0 голосов
/ 17 февраля 2010

Я бы предложил собственное расширение для класса HtmlHelper. Верхняя часть моей головы (возможно наличие синтаксических ошибок), что-то вроде этого

public static class RoleLinksExtension
{
    public static string RoleBasedHomePageLink(this HtmlHelper helper, string text)
    {
        if (user.IsInRole(Role.Admin))
             return helper.ActionLink(text, "Index", "Home", new { area = "Admin" });

        // other role options here

        return string.Empty; // or throw exception
    }
}

Тогда это просто

<%= Html.RoleBasedHomePageLink("Link to home") %>

в вашей разметке.

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

Редактировать : Понятия не имею, почему я не подумал об этом раньше, но если вам нужно нужно перенаправить (возможно, если вам нужна некоторая функциональность перед переходом на главную страницу) , вы можете расширить IPrinciple вместо

public static class AreaHomePageExtensions
{
    public static string GetArea(this IPrinciple user)
    {
        if (user.IsInRole(Role.Admin))
            return "Admin";
        // Other options here
    }
}

Тогда вы можете сделать

return RedirectToAction("Index", "Home", new { area = User.GetArea() });

когда захочешь.

...