在我的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");
}
}
我非常喜欢这种方法,因为我的动作方法符合Single Responsibility Principle。现在,每种方法只处理登录情况或登出情况。我不再需要任何“if”语句来指导流量。
这也应该使单元测试更容易,因为每种方法现在只关注一个结果,而不是两个。我们可以编写单元测试来分别测试每个结果,调用不同的方法。
显然,我不能有两个具有相同签名的方法,这就是我必须使用ActionName属性的原因。
我很感激你的批评。你认为这是一个优雅的解决方案吗?这种方法的优缺点是什么?这有什么安全隐患/风险?
答案 0 :(得分:3)
您遇到的问题是策略模式问题。而且你已经实现了一个非标准的(非标准)策略模式。我担心它太聪明了。这种聪明才能使代码对于那些没有经验的人来说显得不那么明显。
副手,我不喜欢不打扰。我经常将控制器编写为域对象/服务上的非常瘦的适配器。因此,我愿意采取务实的方法来设计控制器的完美性。在决定轻微的设计问题和明显的代码之间,总是选择明显的代码。
如果你有更厚的控制器,或者其他一些在这里真正关心这个问题的原因,你可能会考虑一种更传统的策略模式,也许是一个抽象工厂,它提供了基于身份验证状态的不同策略实现。这符合您的设计目标,并且对其他程序员更熟悉(如果他们了解设计模式)。
所有这一切,我不认为保持聪明的解决方案会伤害到那么多。我很想改名字;拒绝对我来说似乎是一个奇怪的动词。或许AnonymousUsersOnly
,这对未来的程序员来说会更具沟通性。
答案 1 :(得分:0)
我最好选择(伪代码):
PartialView UserProfile() { ... }
PartialView Login() { ... }
并在视野中:
if (User.IsAuthenticated) {
@Html.Action("UserProfile")
} else {
@Html.Action("Login")
}
也可以是DisplayTemplate,帮助器或任何你喜欢的东西,所以你最终使用
@Html.DisplayFor(m=> User)