我有桌面软件开发的背景,我开始学习ASP.NET MVC。
在我的默认HomeController中,我有一个Index动作,其代码如下所示:
if (!Request.IsAuthenticated)
return RedirectToAction("Login", "Account");
换句话说,将用户重定向到“/ account / login”。然后,AccountController.Login操作将处理用户并在他成功登录后将其发送回HomeController。
这段代码对我来说很有趣,也许只是因为我习惯于在桌面软件中做不同的事情。如果我将登录操作的名称更改为“LogOn”怎么办?如果我完全删除AccountController并用其他东西替换它会怎么样?我将介绍一个新的bug,但我不会遇到编译器错误,我的单元测试可能也不会捕获它。由于我使用字符串来指定控制器和动作名称,因此重构和重新设计更有可能在整个地方破坏代码。
我想要的是这样的:
if (!Request.IsAuthenticated)
return RedirectToAction(() => AccountController.Login);
但是我不确定这是否可能,或者这是否是最佳方式。
我是傻瓜,还是其他人有同样的问题?你怎么做才能解决它?
答案 0 :(得分:20)
我认为您正在寻找的是 T4MVC 存在的原因 - 它删除了与控制器和操作相关的所有“魔术字符串”,并用类和属性替换它们
使用T4MVC,这个
if (!Request.IsAuthenticated)
return RedirectToAction("Login", "Account");
变成这个
if (!Request.IsAuthenticated)
return RedirectToAction(MVC.Account.Login());
有一个标志可以在T4MVC设置中设置,以强制它在每个构建上运行模板,在事情发生变化时提供预警。
虽然不是您提出的要求,但您可以考虑使用AuthorizeAttribute
来删除是否需要检查请求是否在控制器操作中进行了身份验证。
此
public class HomeController : Controller
{
public ActionResult Index()
{
if (!Request.IsAuthenticated)
return RedirectToAction("Login", "Account");
// .... carry on
}
}
成为
public class HomeController : Controller
{
[Authorize]
public ActionResult Index()
{
// .... carry on
}
}
然后在web.config
中,将网址设置为指向帐户登录网址
<authentication mode="Forms">
<forms loginUrl="account/login" timeout="30" />
</authentication>
当然,如果您的控制器和操作发生变化(类似于您的原始投诉),这并不会给您带来任何安全感,但您始终可以设置路径将所选URL指向正确的控制器和操作并使用T4MVC路由中生成的类,如果事情发生了变化,会为您提供一些编译时警告。
答案 1 :(得分:4)
您可以编写自己的自定义扩展方法来帮助您避免魔术字符串。例如,您可以在此处查看我的实现: https://github.com/ivaylokenov/ASP.NET-MVC-Lambda-Expression-Helpers 请记住,这会增加一些性能开销运行时间,您可以通过缓存所有链接来解决这些问题。如果您想要编译时检查T4MVC是您的解决方案:http://t4mvc.codeplex.com/
答案 2 :(得分:4)
在C#6中,你可以利用nameof
并轻松地重构许多这些神奇的字符串。
... = new SelectList(context.Set<User>(), nameof(User.UserId), nameof(User.UserName));
...
return RedirectToAction(nameof(Index));
答案 3 :(得分:3)
我知道这不是一个真正的答案,但使用像Resharper这样的工具也可以帮助你解决这个问题。 Resharper会跟踪控制器和操作,并在某些应该是Controller的魔术字符串不是一个时发出警告。它仅适用于RedirectToAction或ActionLink等标准方法。
编辑:显然,您可以添加注释,使其适用于您的自定义扩展方法。请参阅here。
答案 4 :(得分:1)
Russ的回答是正确的,但它并没有真正解决你的担忧..这真的是“为什么MVC中有魔术字符串?”。
在早期版本的MVC中,它实际上是完全不同的。他们没有使用魔术字符串,并且有更多基于类型的方法。但是,由于多种原因,这种情况发生了变化。我已经忘记了细节,但是有一些合理的原因可以解释这种非类型安全方法。
我似乎记得它可能与MVC搜索多个区域的匹配约定的方式有关,而且使用字符串比使用类型对象更容易实现。对于视图和局部视图尤其如此。
也许有人会记住这些细节。
答案 5 :(得分:0)
作为T4MVC的替代品,我编写了一个小帮手,它允许您使用几乎完全建议的语法,而无需自动生成代码:
<a href="@(Url.To<MyController>().MyAction("foo", 42))">link</a>
在控制器中:
return Redirect(Url.To<MyController>().MyAction("foo", 42).ToString());
我的解决方案是在运行时执行T4MVC在构建时执行的操作。
答案 6 :(得分:0)
如果您真的只关心重定向到操作和控制器,那么C#6 nameof
运算符确实非常有用 - 直到您需要在控制器之间重定向。我最后编写了一个实用程序方法来获取控制器名称:
public class Utilities
{
public static string ControllerName<T>() where T : Controller
{
var name = typeof(T).Name;
return name.Substring(0, Math.Max(name.LastIndexOf(nameof(Controller),
StringComparison.CurrentCultureIgnoreCase), 0));
}
}
你可以像这样使用它:
public ActionResult Foo()
{
return RedirectToAction(nameof(HomeController.Index),
Utilities.ControllerName<HomeController>());
}