MVC控制器中的单一责任原则.需要批评



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

例如,我有一个AccountController,它有一个方法"RenderAccountAndProfile"。如果已注销,相应的局部视图将显示登录提示和按钮。如果用户已登录,则会在注销按钮旁边显示用户的配置文件链接。

到目前为止,我在项目中采取的方法是简单地使用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");
}
}

我非常喜欢这种方法,因为我的行动方法符合单一责任原则。现在,每种方法都只处理登录情况或注销情况。我再也不需要任何"如果"语句来引导交通了。

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

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

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

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

顺便说一句,我宁愿不要打扰。我经常将控制器写为域对象/服务上的非常瘦的适配器。因此,我愿意采取务实的方法来设计控制器的完美。在决定是轻微的设计问题还是显而易见的代码时,总是选择显而易见的代码。

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

话虽如此,我不认为保持你聪明的解决方案会对任何事情造成那么大的伤害。我很想改个名字;在我看来,拒绝是一个奇怪的动词。也许AnonymousUsersOnly,对未来的程序员来说会更容易沟通。

我最好选择(伪代码):

PartialView UserProfile() { ... }
PartialView Login() { ... }

并且在视图中:

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

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

@Html.DisplayFor(m=> User)

最新更新