3

在我的 MVC4 应用程序中,根据您是否登录(在我的情况下为 FormsAuthentication),有些操作需要表现不同。

例如,我有一个具有“RenderAccountAndProfile”方法的 AccountController。如果注销,相应的局部视图会显示登录提示和按钮。如果用户已登录,则会显示用户的个人资料链接以及注销按钮。

到目前为止,我在项目中采用的方法是简单地使用 if 语句......

        if (HttpContext.User.Identity.IsAuthenticated)
        {
            ...
        }
        else
        {
            ...
        }

但是,我刚刚创建了一种我认为是这种方法的相当优雅的替代方案。

我创建了一个名为 AnonymousUsersOnly 的新属性,它非常简单:

public class AnonymousUsersOnlyAttribute : System.Web.Mvc.ActionMethodSelectorAttribute
{
    public override bool IsValidForRequest(System.Web.Mvc.ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    {
        return !controllerContext.HttpContext.User.Identity.IsAuthenticated;
    }
}

我的 AccountController 类装饰有 Authorize 属性。这使我能够拥有以下代码:

[Authorize]
public class AccountController : Controller
{
    [AllowAnonymous]
    [AnonymousUsersOnly]
    [ActionName("RenderAccountAndProfile")]
    public ActionResult RenderAccountAndProfile_Anonymous()
    {
        // create a "logged out" view model
        return Content("**NOT LOGGED IN** - LOG IN HERE");
    }

    [ActionName("RenderAccountAndProfile")]
    public ActionResult RenderAccountAndProfile_Authorized()
    {
        // create a "logged in" view model
        return Content("**LOGGED IN** - LOG OUT");
    }
}

我非常喜欢这种方法,因为我的操作方法符合单一职责原则。每种方法现在只处理登录情况或注销情况。我不再需要任何“if”语句来引导流量。

这也应该使单元测试更容易,因为每个方法现在只关注一个结果,而不是两个。我们可以编写单元测试来分别测试每个结果,调用不同的方法。

显然,我不能有两个具有相同签名的方法,所以这就是我必须使用 ActionName 属性的原因。

我会很感激你在这里的批评。你认为这是一个优雅的解决方案吗?这种方法的优缺点是什么?这会带来哪些安全隐患/风险?

4

2 回答 2

3

您在这里遇到的问题是策略模式问题。而且您已经实现了一个(非标准)策略模式,并且实现得非常巧妙。我担心它太聪明了。这种聪明才智使得代码在做的事情对于外行来说不那么明显。

顺便说一句,我宁愿不打扰。我经常将控制器编写为域对象/服务上的非常薄的适配器。因此,我愿意采取务实的态度来完善控制器。在轻微的设计问题和明显的代码之间做出决定时,总是选择明显的代码。

如果你有更厚的控制器,或者有其他原因需要在这里真正关心这个问题,你可能会考虑一个更传统的策略模式,也许有一个抽象工厂的帮助,它提供了基于身份验证状态的不同策略实现。这符合您的设计目标,并且其他程序员会更加熟悉(如果他们知道设计模式)。

话虽如此,我认为保留您的聪明解决方案不会对任何事情造成太大伤害。我很想改名;拒绝对我来说似乎是一个奇怪的动词。也许AnonymousUsersOnly,这对未来的程序员来说会更具交流性。

于 2012-12-09T04:33:39.587 回答
0

我最好选择(伪代码):

PartialView UserProfile() { ... }

PartialView Login() { ... }

并认为:

if (User.IsAuthenticated) {
    @Html.Action("UserProfile")
} else {
    @Html.Action("Login")
}

它也可以是 DisplayTemplate、helper 或任何你喜欢的东西,所以你最终会使用

@Html.DisplayFor(m=> User)
于 2014-07-23T03:06:25.033 回答